


from copy import deepcopy
from pathlib import Path
from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Tuple, Union

import torch
from torch import nn
from torch.utils.data import Dataset

from .deepspeed import is_deepspeed_zeroa_enabled
from .generation.configuration_utils import GenerationConfig
from .trainer import Trainer
from .utils import logging


if TYPE_CHECKING:
	from .data.data_collator import DataCollator
	from .modeling_utils import PreTrainedModel
	from .tokenization_utils_base import PreTrainedTokenizerBase
	from .trainer_callback import TrainerCallback
	from .trainer_utils import EvalPrediction, PredictionOutput
	from .training_args import TrainingArguments


_lowerCAmelCase:	Optional[Any]      							=					logging.get_logger(__name__)




class 			lowercase_				(lowercase__      ):





				def __init__(							self					,     lowercase_ = None					,     lowercase_ = None					,     lowercase_ = None					,     lowercase_ = None					,     lowercase_ = None					,     lowercase_ = None					,     lowercase_ = None					,     lowercase_ = None					,     lowercase_ = None					,     lowercase_ = (None, None)					,     lowercase_ = None					,     )     ->   Optional[int]:
											super().__init__(
											    model=lowercase_					,     args=lowercase_					,     data_collator=lowercase_					,     train_dataset=lowercase_					,     eval_dataset=lowercase_					,     tokenizer=lowercase_					,     model_init=lowercase_					,     compute_metrics=lowercase_					,     callbacks=lowercase_					,     optimizers=lowercase_					,     preprocess_logits_for_metrics=lowercase_					,     )

											# Override self.model.generation_config if a GenerationConfig is specified in args.
											# Priority: args.generation_config > model.generation_config > default GenerationConfig.
											if self.args.generation_config is not None:
																		a__     						=self.load_generation_config(self.args.generation_config)
																		a__     						=gen_config





				@staticmethod
				def 	__UpperCamelCase						(							lowercase_)     ->   GenerationConfig:

											# GenerationConfig provided, nothing to do
											if isinstance(lowercase_					,     lowercase_):
																		return deepcopy(lowercase_)

											# str or Path
											a__     						=Path(lowercase_) if isinstance(lowercase_					,     lowercase_) else gen_config_arg
											a__     						=None

											# Figuring if it is path pointing to a file, pointing to a directory or else a model id or URL
											# This step is required in order to determine config_file_name
											if pretrained_model_name.is_file():
																		a__     						=pretrained_model_name.name
																		a__     						=pretrained_model_name.parent
											# dir path
											elif pretrained_model_name.is_dir():
																		pass
											# model id or URL
											else:
																		a__     						=gen_config_arg

											a__     						=GenerationConfig.from_pretrained(lowercase_					,     lowercase_)
											return gen_config





				def 	__UpperCamelCase						(							self					,     lowercase_ = None					,     lowercase_ = None					,     lowercase_ = "eval"					,     **lowercase_					,     )     ->   Dict[str, float]:
											a__     						=gen_kwargs.copy()
											if gen_kwargs.get('max_length') is None and gen_kwargs.get('max_new_tokens') is None:
																		a__     						=self.args.generation_max_length
											a__     						=(
											    gen_kwargs['num_beams'] if gen_kwargs.get('num_beams') is not None else self.args.generation_num_beams
											)
											a__     						=gen_kwargs

											return super().evaluate(lowercase_					,     ignore_keys=lowercase_					,     metric_key_prefix=lowercase_)





				def 	__UpperCamelCase						(							self					,     lowercase_					,     lowercase_ = None					,     lowercase_ = "test"					,     **lowercase_					,     )     ->   "PredictionOutput":
											a__     						=gen_kwargs.copy()
											if gen_kwargs.get('max_length') is None and gen_kwargs.get('max_new_tokens') is None:
																		a__     						=self.args.generation_max_length
											a__     						=(
											    gen_kwargs['num_beams'] if gen_kwargs.get('num_beams') is not None else self.args.generation_num_beams
											)
											a__     						=gen_kwargs

											return super().predict(lowercase_					,     ignore_keys=lowercase_					,     metric_key_prefix=lowercase_)





				def 	__UpperCamelCase						(							self					,     lowercase_					,     lowercase_					,     lowercase_					,     lowercase_ = None					,     **lowercase_					,     )     ->   Tuple[Optional[float], Optional[torch.Tensor], Optional[torch.Tensor]]:

											if not self.args.predict_with_generate or prediction_loss_only:
																		return super().prediction_step(
																		    lowercase_					,     lowercase_					,     prediction_loss_only=lowercase_					,     ignore_keys=lowercase_)

											a__     						='labels' in inputs
											a__     						=self._prepare_inputs(lowercase_)

											# XXX: adapt synced_gpus for fairscale as well
											# Priority (handled in generate):
											# gen_kwargs > model.generation_config > default GenerationConfig()

											if len(lowercase_) == 0 and hasattr(self					,     '_gen_kwargs'):
																		a__     						=self._gen_kwargs.copy()

											if gen_kwargs.get('max_length') is None and gen_kwargs.get('max_new_tokens') is None:
																		a__     						=self.model.config.max_length
											a__     						=(
											    gen_kwargs['num_beams'] if gen_kwargs.get('num_beams') is not None else self.model.config.num_beams
											)
											a__     						=True if is_deepspeed_zeroa_enabled() else False
											a__     						=(
											    gen_kwargs['synced_gpus'] if gen_kwargs.get('synced_gpus') is not None else default_synced_gpus
											)

											# If the `decoder_input_ids` was created from `labels`, evict the former, so that the model can freely generate
											# (otherwise, it would continue generating from the padded `decoder_input_ids`)
											if (
											    "labels" in inputs
											    and "decoder_input_ids" in inputs
											    and inputs["labels"].shape == inputs["decoder_input_ids"].shape
											):
																		a__     						={k: v for k, v in inputs.items() if k != 'decoder_input_ids'}
											a__     						=self.model.generate(**lowercase_					,     **lowercase_)

											# Temporary hack to ensure the generation config is not initialized for each iteration of the evaluation loop
											# TODO: remove this hack when the legacy code that initializes generation_config from a model config is
											# removed in https://github.com/huggingface/transformers/blob/98d88b23f54e5a23e741833f1e973fdf600cc2c5/src/transformers/generation/utils.py#L1183
											if self.model.generation_config._from_model_config:
																		a__     						=False

											# Retrieves GenerationConfig from model.generation_config
											a__     						=self.model.generation_config
											# in case the batch is shorter than max length, the output should be padded
											if generated_tokens.shape[-1] < gen_config.max_length:
																		a__     						=self._pad_tensors_to_max_len(lowercase_					,     gen_config.max_length)
											elif gen_config.max_new_tokens is not None and generated_tokens.shape[-1] < gen_config.max_new_tokens + 1:
																		a__     						=self._pad_tensors_to_max_len(lowercase_					,     gen_config.max_new_tokens + 1)

											with torch.no_grad():
																		if has_labels:
																									with self.compute_loss_context_manager():
																																a__     						=model(**lowercase_)
																									if self.label_smoother is not None:
																																a__     						=self.label_smoother(lowercase_					,     inputs['labels']).mean().detach()
																									else:
																																a__     						=(outputs['loss'] if isinstance(lowercase_					,     lowercase_) else outputs[0]).mean().detach()
																		else:
																									a__     						=None

											if self.args.prediction_loss_only:
																		return loss, None, None

											if has_labels:
																		a__     						=inputs['labels']
																		if labels.shape[-1] < gen_config.max_length:
																									a__     						=self._pad_tensors_to_max_len(lowercase_					,     gen_config.max_length)
																		elif gen_config.max_new_tokens is not None and labels.shape[-1] < gen_config.max_new_tokens + 1:
																									a__     						=self._pad_tensors_to_max_len(lowercase_					,     gen_config.max_new_tokens + 1)
											else:
																		a__     						=None

											return loss, generated_tokens, labels





				def 	__UpperCamelCase						(							self					,     lowercase_					,     lowercase_)     ->   int:
											if self.tokenizer is not None and hasattr(self.tokenizer					,     'pad_token_id'):
																		# If PAD token is not defined at least EOS token has to be defined
																		a__     						=(
																		    self.tokenizer.pad_token_id if self.tokenizer.pad_token_id is not None else self.tokenizer.eos_token_id
																		)
											else:
																		if self.model.config.pad_token_id is not None:
																									a__     						=self.model.config.pad_token_id
																		else:
																									raise ValueError('Pad_token_id must be set in the configuration of the model, in order to pad tensors')

											a__     						=pad_token_id * torch.ones(
											    (tensor.shape[0], max_length)					,     dtype=tensor.dtype					,     device=tensor.device)
											a__     						=tensor
											return padded_tensor





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


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






def      _lowercase(				__a							:	Namespace    ):
							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 			lowercase_				(lowercase__      ):





				@staticmethod
				def 	__UpperCamelCase						(							lowercase_)     ->   int:
											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=lowercase_					,     required=lowercase_					,     help='The model name, including owner/organization, as seen on the hub.'					,     )
											train_parser.add_argument(
											    '--local-dir'					,     type=lowercase_					,     default=''					,     help='Optional local directory of the model repository. Defaults to /tmp/{model_name}'					,     )
											train_parser.add_argument(
											    '--max-error'					,     type=lowercase_					,     default=lowercase_					,     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=lowercase_					,     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=lowercase_					,     default=lowercase_					,     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=lowercase_)





				@staticmethod
				def 	__UpperCamelCase						(							lowercase_					,     lowercase_)     ->   Optional[int]:
											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(lowercase_					,     lowercase_					,     lowercase_					,     lowercase_=""):
																		# 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(lowercase_					,     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(lowercase_):
																																# If it is a named attribute, we keep the name. Otherwise, just its index.
																																if isinstance(lowercase_					,     lowercase_):
																																							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(lowercase_					,     lowercase_					,     lowercase_					,     lowercase_)

																		return differences

											return _find_pt_tf_differences(lowercase_					,     lowercase_					,     {})





				def __init__(							self					,     lowercase_					,     lowercase_					,     lowercase_					,     lowercase_					,     lowercase_					,     lowercase_					,     lowercase_					,     lowercase_					,     *lowercase_					,     )     ->   str:
											a__     						=logging.get_logger('transformers-cli/pt_to_tf')
											a__     						=model_name
											a__     						=local_dir if local_dir else os.path.join('/tmp'					,     lowercase_)
											a__     						=max_error
											a__     						=new_weights
											a__     						=no_pr
											a__     						=push
											a__     						=extra_commit_description
											a__     						=override_model_class





				def 	__UpperCamelCase						(							self					,     lowercase_					,     lowercase_					,     lowercase_)     ->   List[Any]:

											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(**lowercase_					,     return_tensors='pt')
											a__     						=processor(**lowercase_					,     return_tensors='tf')

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

											return pt_input, tf_input





				def 	__UpperCamelCase						(							self)     ->   str:
											# hub version 0.9.0 introduced the possibility of programmatically opening PRs with normal write tokens.
											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(lowercase_) > 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(lowercase_)
											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(lowercase_					,     lowercase_					,     lowercase_)

											with torch.no_grad():
																		a__     						=pt_model(**lowercase_					,     output_hidden_states=lowercase_)
											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=lowercase_)
											a__     						=tf_from_pt_model(**lowercase_					,     output_hidden_states=lowercase_					,     training=lowercase_)

											# Confirms that cross loading PT weights into TF worked.
											a__     						=self.find_pt_tf_differences(lowercase_					,     lowercase_)
											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(lowercase_) == 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					,     lowercase_)
											a__     						=os.path.join(self._local_dir					,     lowercase_)
											if (not os.path.exists(lowercase_) and not os.path.exists(lowercase_)) 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(**lowercase_					,     output_hidden_states=lowercase_)

											a__     						=self.find_pt_tf_differences(lowercase_					,     lowercase_)
											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(lowercase_) == 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=lowercase_)
																		repo.git_commit(lowercase_)
																		repo.git_push(blocking=lowercase_)  # 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(lowercase_):
																									a__     						=[
																									    CommitOperationAdd(path_in_repo=lowercase_					,     path_or_fileobj=lowercase_)
																									]
																									for shard_path in tf.io.gfile.glob(self._local_dir + '/tf_model-*.h5'):
																																operations += [
																																    CommitOperationAdd(path_in_repo=os.path.basename(lowercase_)					,     path_or_fileobj=lowercase_)
																																]
																		else:
																									a__     						=[CommitOperationAdd(path_in_repo=lowercase_					,     path_or_fileobj=lowercase_)]

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

