class_docstr: A conversion wrapper that takes as an input the `transformers` model to be converted
  and returns the converted `BetterTransformer` model. The `BetterTransformer` model is based on the `BetterTransformer`
  recently released by PyTorch from its 1.12 version:
  https://pytorch.org/blog/a-better-transformer-for-fast-transformer-encoder-inference/
  
  # Original PR from: https://github.com/huggingface/transformers/pull/19553 adapted and wrapped in this script.
docstr: Conversion script from `transformers` model to its BetterTransformers version
  
  Args:
      model (`torch.nn.Module`):
          Original `transformers` model
      keep_original_model (`bool`, defaults to `False`):
          whether to keep or override the original model - essentially
          for memory efficiency reasons
      max_memory (`Optional[Dict]`, defaults to `None`):
          Same argument as `max_memory` argument from `.from_pretrained` function
          in `transformers`.
  Returns:
      The converted model if the conversion has been successful.
docstr_tok: ["Conversion","script","from","`","transformers","`","model","to","its","BetterTransformers","version","Args",":","model","(","`","torch.nn.Module","`",")",":","Original","`","transformers","`","model","keep_original_model","(","`","bool","`",",","defaults","to","`","False","`",")",":","whether","to","keep","or","override","the","original","model","-","essentially","for","memory","efficiency","reasons","max_memory","(","`","Optional","[","Dict","]","`",",","defaults","to","`","None","`",")",":","Same","argument","as","`","max_memory","`","argument","from","`",".from_pretrained","`","function","in","`","transformers","`",".","Returns",":","The","converted","model","if","the","conversion","has","been","successful","."]
code: def transform(
      model: torch.nn.Module,
      keep_original_model: bool = False,
      max_memory: Optional[Dict] = None,
      offload_dir: Optional[Union[str, os.PathLike]] = None,
      **kwargs,
  ) -> torch.nn.Module:
      r"""
      Conversion script from `transformers` model to its BetterTransformers version
  
      Args:
          model (`torch.nn.Module`):
              Original `transformers` model
          keep_original_model (`bool`, defaults to `False`):
              whether to keep or override the original model - essentially
              for memory efficiency reasons
          max_memory (`Optional[Dict]`, defaults to `None`):
              Same argument as `max_memory` argument from `.from_pretrained` function
              in `transformers`.
      Returns:
          The converted model if the conversion has been successful.
      """
  
      hf_config = model.config
      if hf_config.model_type in [
          "falcon",
          "gpt_bigcode",
          "llama",
          "whisper",
      ]:
          raise ValueError(
              f"Transformers now supports natively BetterTransformer optimizations (torch.nn.functional.scaled_dot_product_attention) for the model type {hf_config.model_type}. As such, there is no need to use `model.to_bettertransformers()` or `BetterTransformer.transform(model)` from the Optimum library. Please upgrade to transformers>=4.36 and torch>=2.1.1 to use it. Details: https://huggingface.co/docs/transformers/perf_infer_gpu_one#flashattention-and-memory-efficient-attention-through-pytorchs-scaleddotproductattention."
          )
  
      # Check if we have to load the model using `accelerate`
      if hasattr(model, "hf_device_map"):
          load_accelerate = True
          hf_device_map = model.hf_device_map
      else:
          load_accelerate = False
  
      if (
          hasattr(model, "use_bettertransformer")
          and model.use_bettertransformer is True
      ):
          raise Exception(
              "`BetterTransform.transform()` was called on a model already using Better Transformer modeling."
          )
  
      if BetterTransformerManager.cannot_support(
          model.config.model_type
      ):
          raise ValueError(
              f"The model type {model.config.model_type} can not be supported to be used with BetterTransformer. The identified reason is:"
              f" {BetterTransformerManager.CAN_NOT_BE_SUPPORTED[model.config.model_type]}. Currently supported models are:"
              f" {BetterTransformerManager.MODEL_MAPPING.keys()}."
          )
      if not BetterTransformerManager.supports(model.config.model_type):
          raise NotImplementedError(
              f"The model type {model.config.model_type} is not yet supported to be used with BetterTransformer. Feel free"
              f" to open an issue at https://github.com/huggingface/optimum/issues if you would like this model type to be supported."
              f" Currently supported models are: {BetterTransformerManager.MODEL_MAPPING.keys()}."
          )
  
      if parse(torch.__version__) <= parse("1.14"):
          raise ValueError(
              f"BetterTransformer requires torch>=2.0 but {torch.__version__} is installed. Please upgrade PyTorch."
          )
  
      if load_accelerate:
          # Remove the hooks from the original model to avoid weights being on `meta` device.
          remove_hook_from_module(model, recurse=True)
  
      training_mode = model.training
  
      if keep_original_model:
          try:
              if not check_if_pytorch_greater(
                  2.0,
                  "Please upgrade PyTorch to >=2.0 to use training mode",
              ):
                  model = model.requires_grad_(False)
              model_fast = deepcopy(model)
          except RuntimeError:
              raise ValueError(
                  f"The model {model.__class__.__name__} does not support `deepcopy` operation that is"
                  " internally used to create a copy of the original model when using"
                  " `keep_original_model=True`. Please run the conversion with"
                  " `keep_original_model=False` and create a new copy of the original"
                  " model somewhere else."
              )
          model_fast = replace_to_bettertransformer(
              model_fast, hf_config
          )
      else:
          model_fast = replace_to_bettertransformer(model, hf_config)
          model = None
  
      if BetterTransformerManager.requires_nested_tensor(
          model_fast.config.model_type
      ):
          set_last_layer(model_fast)
  
      # Add a class arguments, we might need to identify whether the model
      # has been correctly converted to its `BetterTransformer` version.
      setattr(model_fast, "use_bettertransformer", True)
  
      if load_accelerate:
          all_model_tensors = [
              name for name, _ in model_fast.state_dict().items()
          ]
          for module_name in hf_device_map.keys():
              all_model_tensors = [
                  name
                  for name in all_model_tensors
                  if not name.startswith(module_name)
              ]
  
          if len(all_model_tensors) > 0:
              # This is the case where a transformed submodule is broken into several devices:
              # as the submodules map may differ, we need to reinfer the device map
              bt_device_map = infer_auto_device_map(
                  model_fast, max_memory=max_memory
              )
          else:
              bt_device_map = hf_device_map
  
          model_fast = dispatch_model(
              model_fast, bt_device_map, offload_dir=offload_dir
          )
  
          # It is not recommended to have `keep_original_model=True` with a model
          # that is loaded with accelerate but just in case
          if keep_original_model:
              model = dispatch_model(
                  model, hf_device_map, offload_dir=offload_dir
              )
  
      # See: https://github.com/pytorch/pytorch/issues/96099
      logger.warning(
          "The BetterTransformer implementation"
          " does not support padding during training, as the fused kernels do not support"
          " attention masks. Beware that passing padded batched data during training may result in unexpected outputs. Please refer to https://huggingface.co/docs/optimum/bettertransformer/overview for more details."
      )
  
      # Overwrite the `save_pretrained` method
      # by raising an error if the user tries to save the model
      # or push it to the hub.
      model_fast._old_save_pretrained = model_fast.save_pretrained
      model_fast._old_push_to_hub = model_fast.push_to_hub
  
      model_fast.save_pretrained = raise_save_or_push_incompatible
      model_fast.push_to_hub = raise_save_or_push_incompatible
  
      if training_mode:
          model_fast = model_fast.train()
      else:
          model_fast = model_fast.eval()
  
      return model_fast
  
file_path: optimum/optimum/bettertransformer/transformation.py
imports: import logging
  import os
  import types
  from copy import deepcopy
  from typing import TYPE_CHECKING, Dict, Optional, Union
  import torch
  from packaging.version import parse
  from ..utils import check_if_pytorch_greater, is_accelerate_available, recurse_getattr, recurse_setattr
  from .models import BetterTransformerManager
label_desc: Use image node_id 1 for calling the BetterTransformer obj's underlying member method code with example usage: obj.transform(model, keep_original_model, max_memory, offload_dir) and returns: model_fast