



import inspect
import os
from argparse import ArgumentParser, Namespace
from importlib import import_module

import huggingface_hub
import numpy as np
from packaging import version

from .. import (
    FEATURE_EXTRACTOR_MAPPING,
    IMAGE_PROCESSOR_MAPPING,
    PROCESSOR_MAPPING,
    TOKENIZER_MAPPING,
    AutoConfig,
    AutoFeatureExtractor,
    AutoImageProcessor,
    AutoProcessor,
    AutoTokenizer,
    is_datasets_available,
    is_tf_available,
    is_torch_available,
)
from ..utils import TF2_WEIGHTS_INDEX_NAME, TF2_WEIGHTS_NAME, logging
from . import BaseTransformersCLICommand


if is_tf_available():
	import tensorflow as tf

	tf.config.experimental.enable_tensor_float_aa_execution(False)

if is_torch_available():
	import torch

if is_datasets_available():
	from datasets import load_dataset


_lowercase				:					List[Any]     					=5e-5  # larger error tolerance than in our internal tests, to avoid flaky user-facing errors




def    UpperCAmelCase					(  lowercase__						:					Namespace	):



			'''simple docstring'''





			return PTtoTFCommand(
			    args.model_name				,					args.local_dir				,					args.max_error				,					args.new_weights				,					args.no_pr				,					args.push				,					args.extra_commit_description				,					args.override_model_class				,					)





class lowerCAmelCase_       (   A_			):







	'''simple docstring'''




	@staticmethod
	def 				_A			(	lowerCamelCase       ):



				'''simple docstring'''


				a__					=  parser.add_parser(
				    """pt-to-tf"""   ,       help=(
				        """CLI tool to run convert a transformers model from a PyTorch checkpoint to a TensorFlow checkpoint."""
				        """ Can also be used to validate existing weights without opening PRs, with --no-pr."""
				    )   ,       )
				train_parser.add_argument(
				    """--model-name"""   ,       type=lowerCamelCase   ,       required=lowerCamelCase   ,       help="""The model name, including owner/organization, as seen on the hub."""   ,       )
				train_parser.add_argument(
				    """--local-dir"""   ,       type=lowerCamelCase   ,       default=""""""   ,       help="""Optional local directory of the model repository. Defaults to /tmp/{model_name}"""   ,       )
				train_parser.add_argument(
				    """--max-error"""   ,       type=lowerCamelCase   ,       default=lowerCamelCase   ,       help=(
				        f'Maximum error tolerance. Defaults to {MAX_ERROR}. This flag should be avoided, use at your own risk.'
				    )   ,       )
				train_parser.add_argument(
				    """--new-weights"""   ,       action="""store_true"""   ,       help="""Optional flag to create new TensorFlow weights, even if they already exist."""   ,       )
				train_parser.add_argument(
				    """--no-pr"""   ,       action="""store_true"""   ,       help="""Optional flag to NOT open a PR with converted weights."""       )
				train_parser.add_argument(
				    """--push"""   ,       action="""store_true"""   ,       help="""Optional flag to push the weights directly to `main` (requires permissions)"""   ,       )
				train_parser.add_argument(
				    """--extra-commit-description"""   ,       type=lowerCamelCase   ,       default=""""""   ,       help="""Optional additional commit description to use when opening a PR (e.g. to tag the owner)."""   ,       )
				train_parser.add_argument(
				    """--override-model-class"""   ,       type=lowerCamelCase   ,       default=lowerCamelCase   ,       help="""If you think you know better than the auto-detector, you can specify the model class here. """
				    """Can be either an AutoModel class or a specific model class like BertForSequenceClassification."""   ,       )
				train_parser.set_defaults(func=lowerCamelCase       )

	@staticmethod
	def 				_A			(	lowerCamelCase   ,       lowerCamelCase       ):



				'''simple docstring'''


				a__					=  set(pt_outputs.keys()       )
				a__					=  set(tf_outputs.keys()       )
				if pt_out_attrs != tf_out_attrs:
							raise ValueError(
							    f'The model outputs have different attributes, aborting. (Pytorch: {pt_out_attrs}, TensorFlow:'
							    f' {tf_out_attrs})'       )

				# 2. For each output attribute, computes the difference
				def _find_pt_tf_differences(lowerCamelCase   ,       lowerCamelCase   ,       lowerCamelCase   ,       lowerCamelCase=""       ):
							# If the current attribute is a tensor, it is a leaf and we make the comparison. Otherwise, we will dig in
							# recursivelly, keeping the name of the attribute.
							if isinstance(lowerCamelCase   ,       torch.Tensor       ):
										a__					=  np.max(np.abs(pt_out.numpy() - tf_out.numpy()       )       )
										a__					=  tensor_difference
							else:
										a__					=  attr_name
										for i, pt_item in enumerate(lowerCamelCase       ):
													# If it is a named attribute, we keep the name. Otherwise, just its index.
													if isinstance(lowerCamelCase   ,       lowerCamelCase       ):
																a__					=  root_name + pt_item
																a__					=  tf_out[pt_item]
																a__					=  pt_out[pt_item]
													else:
																a__					=  root_name + f'[{i}]'
																a__					=  tf_out[i]
													a__					=  _find_pt_tf_differences(lowerCamelCase   ,       lowerCamelCase   ,       lowerCamelCase   ,       lowerCamelCase       )

							return differences

				return _find_pt_tf_differences(lowerCamelCase   ,       lowerCamelCase   ,       {}       )

	def __init__(	self   ,       lowerCamelCase   ,       lowerCamelCase   ,       lowerCamelCase   ,       lowerCamelCase   ,       lowerCamelCase   ,       lowerCamelCase   ,       lowerCamelCase   ,       lowerCamelCase   ,       *lowerCamelCase   ,       ):



				'''simple docstring'''


				a__					=  logging.get_logger("""transformers-cli/pt_to_tf"""       )
				a__					=  model_name
				a__					=  local_dir if local_dir else os.path.join("""/tmp"""   ,       lowerCamelCase       )
				a__					=  max_error
				a__					=  new_weights
				a__					=  no_pr
				a__					=  push
				a__					=  extra_commit_description
				a__					=  override_model_class

	def 				_A			(	self   ,       lowerCamelCase   ,       lowerCamelCase   ,       lowerCamelCase       ):



				'''simple docstring'''


				def _get_audio_input():
							a__					=  load_dataset("""hf-internal-testing/librispeech_asr_dummy"""   ,       """clean"""   ,       split="""validation"""       )
							a__					=  ds.sort("""id"""       ).select(range(2       )       )[:2]["""audio"""]
							a__					=  [x["""array"""] for x in speech_samples]
							return raw_samples

				a__					=  type(pt_model.config       )
				if model_config_class in PROCESSOR_MAPPING:
							a__					=  AutoProcessor.from_pretrained(self._local_dir       )
							if model_config_class in TOKENIZER_MAPPING and processor.tokenizer.pad_token is None:
										a__					=  processor.tokenizer.eos_token
				elif model_config_class in IMAGE_PROCESSOR_MAPPING:
							a__					=  AutoImageProcessor.from_pretrained(self._local_dir       )
				elif model_config_class in FEATURE_EXTRACTOR_MAPPING:
							a__					=  AutoFeatureExtractor.from_pretrained(self._local_dir       )
				elif model_config_class in TOKENIZER_MAPPING:
							a__					=  AutoTokenizer.from_pretrained(self._local_dir       )
							if processor.pad_token is None:
										a__					=  processor.eos_token
				else:
							raise ValueError(f'Unknown data processing type (model config type: {model_config_class})'       )

				a__					=  set(inspect.signature(pt_model.forward       ).parameters.keys()       )
				a__					=  {}
				if "input_ids" in model_forward_signature:
							processor_inputs.update(
							    {
							        """text""": ["""Hi there!""", """I am a batch with more than one row and different input lengths."""],
							        """padding""": True,
							        """truncation""": True,
							    }       )
				if "pixel_values" in model_forward_signature:
							a__					=  load_dataset("""cifar10"""   ,       """plain_text"""   ,       split="""test"""       )[:2]["""img"""]
							processor_inputs.update({"""images""": sample_images}       )
				if "input_features" in model_forward_signature:
							a__					=  inspect.signature(processor.feature_extractor       ).parameters
							# Pad to the largest input length by default but take feature extractor default
							# padding value if it exists e.g. "max_length" and is not False or None
							if "padding" in feature_extractor_signature:
										a__					=  feature_extractor_signature["""padding"""].default
										if default_strategy is not False and default_strategy is not None:
													a__					=  default_strategy
										else:
													a__					=  True
							else:
										a__					=  True
							processor_inputs.update({"""audio""": _get_audio_input(), """padding""": padding_strategy}       )
				if "input_values" in model_forward_signature:  # Wav2Vec2 audio input
							processor_inputs.update({"""audio""": _get_audio_input(), """padding""": True}       )
				a__					=  processor(**lowerCamelCase   ,       return_tensors="""pt"""       )
				a__					=  processor(**lowerCamelCase   ,       return_tensors="""tf"""       )

				# Extra input requirements, in addition to the input modality
				if (
				    config.is_encoder_decoder
				    or (hasattr(lowerCamelCase   ,       """encoder"""       ) and hasattr(lowerCamelCase   ,       """decoder"""       ))
				    or "decoder_input_ids" in tf_dummy_inputs
				):
							a__					=  np.asarray([[1], [1]]   ,       dtype=lowerCamelCase       ) * (pt_model.config.decoder_start_token_id or 0)
							pt_input.update({"""decoder_input_ids""": torch.tensor(lowerCamelCase       )}       )
							tf_input.update({"""decoder_input_ids""": tf.convert_to_tensor(lowerCamelCase       )}       )

				return pt_input, tf_input







	def 				_A			(	self       ):



				'''simple docstring'''


				if version.parse(huggingface_hub.__version__       ) < version.parse("""0.9.0"""       ):
							raise ImportError(
							    """The huggingface_hub version must be >= 0.9.0 to use this command. Please update your huggingface_hub"""
							    """ installation."""       )
				else:
							from huggingface_hub import Repository, create_commit
							from huggingface_hub._commit_api import CommitOperationAdd

				# Fetch remote data
				a__					=  Repository(local_dir=self._local_dir   ,       clone_from=self._model_name       )

				# Load config and get the appropriate architecture -- the latter is needed to convert the head's weights
				a__					=  AutoConfig.from_pretrained(self._local_dir       )
				a__					=  config.architectures
				if self._override_model_class is not None:
							if self._override_model_class.startswith("""TF"""       ):
										a__					=  [self._override_model_class[2:]]
							else:
										a__					=  [self._override_model_class]
							try:
										a__					=  getattr(import_module("""transformers"""       )   ,       architectures[0]       )
							except AttributeError:
										raise ValueError(f'Model class {self._override_model_class} not found in transformers.'       )
							try:
										a__					=  getattr(import_module("""transformers"""       )   ,       """TF""" + architectures[0]       )
							except AttributeError:
										raise ValueError(f'TF model class TF{self._override_model_class} not found in transformers.'       )
				elif architectures is None:  # No architecture defined -- use auto classes
							a__					=  getattr(import_module("""transformers"""       )   ,       """AutoModel"""       )
							a__					=  getattr(import_module("""transformers"""       )   ,       """TFAutoModel"""       )
							self._logger.warning("""No detected architecture, using AutoModel/TFAutoModel"""       )
				else:  # Architecture defined -- use it
							if len(lowerCamelCase       ) > 1:
										raise ValueError(f'More than one architecture was found, aborting. (architectures = {architectures})'       )
							self._logger.warning(f'Detected architecture: {architectures[0]}'       )
							a__					=  getattr(import_module("""transformers"""       )   ,       architectures[0]       )
							try:
										a__					=  getattr(import_module("""transformers"""       )   ,       """TF""" + architectures[0]       )
							except AttributeError:
										raise AttributeError(f'The TensorFlow equivalent of {architectures[0]} doesn\'t exist in transformers.'       )

        # Check the TF dummy inputs to see what keys we need in the forward pass
				a__					=  tf_class.from_config(lowerCamelCase       )
				a__					=  tf_from_pt_model.dummy_inputs

				del tf_from_pt_model  # Try to keep only one model in memory at a time

				# Load the model and get some basic inputs
				a__					=  pt_class.from_pretrained(self._local_dir       )
				pt_model.eval()

				a__				,       a__					=  self.get_inputs(lowerCamelCase   ,       lowerCamelCase   ,       lowerCamelCase       )

				with torch.no_grad():
							a__					=  pt_model(**lowerCamelCase   ,       output_hidden_states=lowerCamelCase       )
				del pt_model  # will no longer be used, and may have a large memory footprint

				a__					=  tf_class.from_pretrained(self._local_dir   ,       from_pt=lowerCamelCase       )
				a__					=  tf_from_pt_model(**lowerCamelCase   ,       output_hidden_states=lowerCamelCase   ,       training=lowerCamelCase       )

				# Confirms that cross loading PT weights into TF worked.
				a__					=  self.find_pt_tf_differences(lowerCamelCase   ,       lowerCamelCase       )
				a__					=  {k: v for k, v in crossload_differences.items() if """hidden""" not in k}
				a__					=  {k: v for k, v in crossload_differences.items() if """hidden""" in k}
				if len(lowerCamelCase       ) == 0 and architectures is not None:
							raise ValueError(
							    f'Something went wrong -- the config file has architectures ({architectures}), but no model head'
							    """ output was found. All outputs start with 'hidden'"""       )
				a__					=  max(output_differences.values()       ) if output_differences else 0.0
				a__					=  max(hidden_differences.values()       )
				if max_crossload_output_diff > self._max_error or max_crossload_hidden_diff > self._max_error:
							raise ValueError(
							    """The cross-loaded TensorFlow model has different outputs, something went wrong!\n"""
							    + f'\nList of maximum output differences above the threshold ({self._max_error}):\n'
							    + """\n""".join([f'{k}: {v:.3e}' for k, v in output_differences.items() if v > self._max_error]       )
							    + f'\n\nList of maximum hidden layer differences above the threshold ({self._max_error}):\n'
							    + """\n""".join([f'{k}: {v:.3e}' for k, v in hidden_differences.items() if v > self._max_error]       )       )

				# Save the weights in a TF format (if needed) and confirms that the results are still good
				a__					=  os.path.join(self._local_dir   ,       lowerCamelCase       )
				a__					=  os.path.join(self._local_dir   ,       lowerCamelCase       )
				if (not os.path.exists(lowerCamelCase       ) and not os.path.exists(lowerCamelCase       )) or self._new_weights:
							tf_from_pt_model.save_pretrained(self._local_dir       )
				del tf_from_pt_model  # will no longer be used, and may have a large memory footprint

				a__					=  tf_class.from_pretrained(self._local_dir       )
				a__					=  tf_model(**lowerCamelCase   ,       output_hidden_states=lowerCamelCase       )

				a__					=  self.find_pt_tf_differences(lowerCamelCase   ,       lowerCamelCase       )
				a__					=  {k: v for k, v in conversion_differences.items() if """hidden""" not in k}
				a__					=  {k: v for k, v in conversion_differences.items() if """hidden""" in k}
				if len(lowerCamelCase       ) == 0 and architectures is not None:
							raise ValueError(
							    f'Something went wrong -- the config file has architectures ({architectures}), but no model head'
							    """ output was found. All outputs start with 'hidden'"""       )
				a__					=  max(output_differences.values()       ) if output_differences else 0.0
				a__					=  max(hidden_differences.values()       )
				if max_conversion_output_diff > self._max_error or max_conversion_hidden_diff > self._max_error:
							raise ValueError(
							    """The converted TensorFlow model has different outputs, something went wrong!\n"""
							    + f'\nList of maximum output differences above the threshold ({self._max_error}):\n'
							    + """\n""".join([f'{k}: {v:.3e}' for k, v in output_differences.items() if v > self._max_error]       )
							    + f'\n\nList of maximum hidden layer differences above the threshold ({self._max_error}):\n'
							    + """\n""".join([f'{k}: {v:.3e}' for k, v in hidden_differences.items() if v > self._max_error]       )       )

				a__					=  """Update TF weights""" if self._new_weights else """Add TF weights"""
				if self._push:
							repo.git_add(auto_lfs_track=lowerCamelCase       )
							repo.git_commit(lowerCamelCase       )
							repo.git_push(blocking=lowerCamelCase       )  # this prints a progress bar with the upload
							self._logger.warning(f'TF weights pushed into {self._model_name}'       )
				elif not self._no_pr:
							self._logger.warning("""Uploading the weights into a new PR..."""       )
							a__					=  (
							    """Model converted by the [`transformers`' `pt_to_tf`"""
							    """ CLI](https://github.com/huggingface/transformers/blob/main/src/transformers/commands/pt_to_tf.py). """
							    """All converted model outputs and hidden layers were validated against its PyTorch counterpart.\n\n"""
							    f'Maximum crossload output difference={max_crossload_output_diff:.3e}; '
							    f'Maximum crossload hidden layer difference={max_crossload_hidden_diff:.3e};\n'
							    f'Maximum conversion output difference={max_conversion_output_diff:.3e}; '
							    f'Maximum conversion hidden layer difference={max_conversion_hidden_diff:.3e};\n'
							)
							if self._max_error > MAX_ERROR:
										commit_descrition += (
										    f'\n\nCAUTION: The maximum admissible error was manually increased to {self._max_error}!'
										)
							if self._extra_commit_description:
										commit_descrition += "\n\n" + self._extra_commit_description

							# sharded model -> adds all related files (index and .h5 shards)
							if os.path.exists(lowerCamelCase       ):
										a__					=  [
										    CommitOperationAdd(path_in_repo=lowerCamelCase   ,       path_or_fileobj=lowerCamelCase       )
										]
										for shard_path in tf.io.gfile.glob(self._local_dir + """/tf_model-*.h5"""       ):
													operations += [
													    CommitOperationAdd(path_in_repo=os.path.basename(lowerCamelCase       )   ,       path_or_fileobj=lowerCamelCase       )
													]
							else:
										a__					=  [CommitOperationAdd(path_in_repo=lowerCamelCase   ,       path_or_fileobj=lowerCamelCase       )]

							a__					=  create_commit(
							    repo_id=self._model_name   ,       operations=lowerCamelCase   ,       commit_message=lowerCamelCase   ,       commit_description=lowerCamelCase   ,       repo_type="""model"""   ,       create_pr=lowerCamelCase   ,       ).pr_url
							self._logger.warning(f'PR open in {hub_pr_url}'       )






from typing import Any

import numpy as np




def    UpperCAmelCase					(  lowercase__						:					np.ndarray	):



			'''simple docstring'''





			assert np.shape(lowercase__	)[0] == np.shape(lowercase__	)[1]

			# If matrix not symmetric, exit right away.
			if np.allclose(lowercase__				,					matrix.T	) is False:
						return False

			# Get eigenvalues and eignevectors for a symmetric matrix.
			a__				,       a__					=  np.linalg.eigh(lowercase__	)

			# Check sign of all eigenvalues.
			# np.all returns a value of type np.bool_
			return bool(np.all(eigen_values > 0	)	)




def    UpperCAmelCase					(  lowercase__						:					int	):



			'''simple docstring'''





			a__					=  np.random.randn(lowercase__				,					lowercase__	)
			a__					=  np.dot(lowercase__				,					random_matrix.T	)
			assert _is_matrix_spd(lowercase__	)
			return spd_matrix




def    UpperCAmelCase					(  lowercase__						:					np.ndarray				,					lowercase__						:					np.ndarray				,					lowercase__						:					int = 1000				,					lowercase__						:					float = 1e-8				,					):



			'''simple docstring'''





			assert np.shape(lowercase__	)[0] == np.shape(lowercase__	)[1]
			assert np.shape(lowercase__	)[0] == np.shape(lowercase__	)[0]
			assert _is_matrix_spd(lowercase__	)

			# Initialize solution guess, residual, search direction.
			a__					=  np.zeros((np.shape(lowercase__	)[0], 1)	)
			a__					=  np.copy(lowercase__	)
			a__					=  np.copy(lowercase__	)

			# Set initial errors in solution guess and residual.
			a__					=  1e9
			a__					=  1e9
			a__					=  1e9

			# Set iteration counter to threshold number of iterations.
			a__					=  0

			while error > tol:
						# Save this value so we only calculate the matrix-vector product once.
						a__					=  np.dot(lowercase__				,					lowercase__	)

						# The main algorithm.

						# Update search direction magnitude.
						a__					=  np.dot(ra.T				,					lowercase__	) / np.dot(pa.T				,					lowercase__	)
						# Update solution guess.
						a__					=  xa + alpha * pa
						# Calculate new residual.
						a__					=  ra - alpha * w
						# Calculate new Krylov subspace scale.
						a__					=  np.dot(r.T				,					lowercase__	) / np.dot(ra.T				,					lowercase__	)
						# Calculate new A conjuage search direction.
						a__					=  r + beta * pa

						# Calculate errors.
						a__					=  np.linalg.norm(r - ra	)
						a__					=  np.linalg.norm(x - xa	)
						a__					=  np.maximum(lowercase__				,					lowercase__	)

						# Update variables.
						a__					=  np.copy(lowercase__	)
						a__					=  np.copy(lowercase__	)
						a__					=  np.copy(lowercase__	)

						# Update number of iterations.
						iterations += 1
						if iterations > max_iterations:
									break

			return x




def    UpperCAmelCase					(  ):



			'''simple docstring'''





			a__					=  3
			a__					=  _create_spd_matrix(lowercase__	)
			a__					=  np.random.randn(lowercase__				,					1	)
			a__					=  np.dot(lowercase__				,					lowercase__	)

			# Numpy solution.
			a__					=  np.linalg.solve(lowercase__				,					lowercase__	)

			# Our implementation.
			a__					=  conjugate_gradient(lowercase__				,					lowercase__	)

			# Ensure both solutions are close to x_true (and therefore one another).
			assert np.linalg.norm(x_numpy - x_true	) <= 1e-6
			assert np.linalg.norm(x_conjugate_gradient - x_true	) <= 1e-6


if __name__ == "__main__":
	import doctest

	doctest.testmod()
	test_conjugate_gradient()

