text: # !/usr/bin/env python
  # coding=UTF-8
  """
  @Author: WEN Hao
  @LastEditors: WEN Hao
  @Description:
  @Date: 2021-09-09
  @LastEditTime: 2021-12-23
  
  Crafting Adversarial Input Sequences For Recurrent Neural Networks
  
  https://arxiv.org/abs/1604.08275
  
  状态
  -----
  代码完成        √
  手动测试完成    √
  自动测试完成    X
  文档完成        √
  """
  
  import time
  from typing import NoReturn, Any, Optional
  
  import torch
  
  from .attack import Attack
  from Models.base import NLPVictimModel
  from utils.constraints import (  # noqa: F401
      InputColumnModification,
      RepeatModification,
      StopwordModification,
  )
  from utils.goal_functions import UntargetedClassification
  from utils.search_methods import WordImportanceRanking
  from utils.transformations import WordEmbeddingGradientSignSubstitute
  from utils.assets import fetch
  from utils.strings import normalize_language, LANGUAGE
  from utils.word_embeddings import (  # noqa: F401
      GensimWordEmbedding,
      CounterFittedEmbedding,
      ChineseWord2Vec,
  )
  from Models.TestModel.bert_amazon_zh import VictimBERTAmazonZH
  from Models.TestModel.roberta_sst import VictimRoBERTaSST
  
  
  __all__ = [
      "FD",
  ]
  
  
  class FD(Attack):
      """ """
  
      __name__ = "FD"
  
      def __init__(
          self,
          model: Optional[NLPVictimModel] = None,
          device: Optional[torch.device] = None,
          language: str = "zh",
          **kwargs: Any,
      ) -> NoReturn:
          """
          @description: The Boundary Attack
          @param {
              model:
              device:
              kwargs:
          }
          @return: None
          """
          self.__initialized = False
          self.__valid_params = {
              "top_n",
              "verbose",
          }
          self._language = normalize_language(language)
          self._model = model
          if not self._model:
              start = time.time()
              if self._language == LANGUAGE.CHINESE:
                  print("load default Chinese victim model...")
                  self._model = VictimBERTAmazonZH()
              else:
                  print("load default English victim model...")
                  self._model = VictimRoBERTaSST()
              print(f"default model loaded in {time.time()-start:.2f} seconds.")
          self._device = device
          self._parse_params(**kwargs)
  
      def _parse_params(self, **kwargs):
          """ """
          assert set(kwargs).issubset(self.__valid_params)
          if self.__initialized:
              self.__reset_params(**kwargs)
          self.__parse_params(**kwargs)
          self.__initialized = True
  
      def __parse_params(self, **kwargs):
          """
          @description:
          @param {
              kwargs:
          }
          @return:
          """
          #
          # Don't modify the same word twice or the stopwords defined
          # in the TextFooler public implementation.
          #
          # fmt: off
          verbose = kwargs.get("verbose", 0)
          print("start initializing attacking parameters...")
          start = time.time()
          print("loading stopwords and word embedding...")
          if self._language == LANGUAGE.CHINESE:
              stopwords = fetch("stopwords_zh")
              embedding = ChineseWord2Vec()
          elif self._language == LANGUAGE.ENGLISH:
              stopwords = fetch("stopwords_en")
              embedding = CounterFittedEmbedding()
          else:
              raise ValueError(f"暂不支持语言 {self._language.name.lower()}")
          print(f"stopwords and word embedding loaded in {time.time()-start:.2f} seconds")
  
          # fmt: on
          constraints = [RepeatModification(), StopwordModification(stopwords=stopwords)]
          #
          # During entailment, we should only edit the hypothesis - keep the premise
          # the same.
          #
          input_column_modification = InputColumnModification(
              ["premise", "hypothesis"], {"premise"}
          )
          constraints.append(input_column_modification)
  
          #
          # Goal is untargeted classification
          #
          goal_function = UntargetedClassification(self._model)
  
          #
          # random search
          #
          search_method = WordImportanceRanking(wir_method="random", verbose=verbose)
  
          #
          # transform by word embedding
          #
          top_n = kwargs.get("top_n", 5)
          transformation = WordEmbeddingGradientSignSubstitute(
              language=self._language,
              embedding=embedding,
              model_wrapper=self._model,
              top_n=top_n,
              verbose=verbose,
          )
  
          super().__init__(
              model=self._model,
              device=self._device,
              IsTargeted=False,
              goal_function=goal_function,
              constraints=constraints,
              transformation=transformation,
              search_method=search_method,
              language=self._language,
              verbose=verbose,
          )
  
      def __reset_params(self, **kwargs: Any) -> NoReturn:
          """ """
          if "top_n" in kwargs:
              self.transformation.top_n = kwargs.get("top_n")
          self.verbose = kwargs.get("verbose", self.verbose)
  
      def prepare_data(self):
          """ """
          raise NotImplementedError("请勿调用此方法")
  
      def generate(self):
          """ """
          raise NotImplementedError("请勿调用此方法")
  