"""simple docstring"""
import importlib.metadata
import warnings
from copy import deepcopy

from packaging import version

from ..utils import logging
from .import_utils import is_accelerate_available, is_bitsandbytes_available


if is_bitsandbytes_available():
					import bitsandbytes as bnb
					import torch
					import torch.nn as nn

					from ..pytorch_utils import ConvaD

if is_accelerate_available():
					from accelerate import init_empty_weights
					from accelerate.utils import find_tied_parameters

SCREAMING_SNAKE_CASE__   =					logging.get_logger(__name__)





def 				lowerCAmelCase__      (     _UpperCamelCase    :			List[str]	,     _UpperCamelCase    :			Union[str, Any]	,     _UpperCamelCase    :			List[Any]	,     _UpperCamelCase    :			Optional[Any]=None	,     _UpperCamelCase    :			Dict=None   )   ->			Union[str, Any]:





						"""simple docstring"""






						if "." in tensor_name:
												snake_case        =     tensor_name.split('.'   )
												for split in splits[:-1]:
																		snake_case        =     getattr(_UpperCamelCase	,     _UpperCamelCase   )
																		if new_module is None:
																								raise ValueError(f"""{module} has no attribute {split}."""   )
																		snake_case        =     new_module
												snake_case        =     splits[-1]

						if tensor_name not in module._parameters and tensor_name not in module._buffers:
												raise ValueError(f"""{module} does not have a parameter or a buffer named {tensor_name}."""   )
						snake_case        =     tensor_name in module._buffers
						snake_case        =     getattr(_UpperCamelCase	,     _UpperCamelCase   )

						if old_value.device == torch.device('meta'   ) and device not in ["meta", torch.device('meta'   )] and value is None:
												raise ValueError(f"""{tensor_name} is on the meta device, we need a `value` to put in on {device}."""   )

						snake_case        =     False
						snake_case        =     False
						if is_buffer or not is_bitsandbytes_available():
												snake_case        =     False
												snake_case        =     False
						else:
												snake_case        =     hasattr(bnb.nn	,     'Params4bit'   ) and isinstance(module._parameters[tensor_name]	,     bnb.nn.Paramsabit   )
												snake_case        =     isinstance(module._parameters[tensor_name]	,     bnb.nn.IntaParams   )

						if is_abit or is_abit:
												snake_case        =     module._parameters[tensor_name]
												if param.device.type != "cuda":
																		if value is None:
																								snake_case        =     old_value.to(_UpperCamelCase   )
																		elif isinstance(_UpperCamelCase	,     torch.Tensor   ):
																								snake_case        =     value.to('cpu'   )
																								if value.dtype == torch.inta:
																														snake_case        =     version.parse(importlib.metadata.version('bitsandbytes'   )   ) > version.parse(
																														    '0.37.2'   )
																														if not is_abit_serializable:
																																				raise ValueError(
																																				    'Detected int8 weights but the version of bitsandbytes is not compatible with int8 serialization. '
																																				    'Make sure to download the latest `bitsandbytes` version. `pip install --upgrade bitsandbytes`.'   )
																		else:
																								snake_case        =     torch.tensor(_UpperCamelCase	,     device='cpu'   )

																		# Support models using `Conv1D` in place of `nn.Linear` (e.g. gpt2) by transposing the weight matrix prior to quantization.
																		# Since weights are saved in the correct "orientation", we skip transposing when loading.
																		if issubclass(module.source_cls	,     _UpperCamelCase   ) and fpaa_statistics is None:
																								snake_case        =     new_value.T

																		snake_case        =     old_value.__dict__
																		if is_abit:
																								snake_case        =     bnb.nn.IntaParams(_UpperCamelCase	,     requires_grad=_UpperCamelCase	,     **_UpperCamelCase   ).to(_UpperCamelCase   )
																		elif is_abit:
																								snake_case        =     bnb.nn.Paramsabit(_UpperCamelCase	,     requires_grad=_UpperCamelCase	,     **_UpperCamelCase   ).to(_UpperCamelCase   )

																		snake_case        =     new_value
																		if fpaa_statistics is not None:
																								setattr(module.weight	,     'SCB'	,     fpaa_statistics.to(_UpperCamelCase   )   )

						else:
												if value is None:
																		snake_case        =     old_value.to(_UpperCamelCase   )
												elif isinstance(_UpperCamelCase	,     torch.Tensor   ):
																		snake_case        =     value.to(_UpperCamelCase   )
												else:
																		snake_case        =     torch.tensor(_UpperCamelCase	,     device=_UpperCamelCase   )

												if is_buffer:
																		snake_case        =     new_value
												else:
																		snake_case        =     nn.Parameter(_UpperCamelCase	,     requires_grad=old_value.requires_grad   )
																		snake_case        =     new_value





def 				lowerCAmelCase__      (     _UpperCamelCase    :			List[str]	,     _UpperCamelCase    :			Tuple=None	,     _UpperCamelCase    :			Tuple=None	,     _UpperCamelCase    :			Optional[Any]=None	,     _UpperCamelCase    :			Optional[int]=False   )   ->			Optional[int]:





						"""simple docstring"""






						for name, module in model.named_children():
												if current_key_name is None:
																		snake_case        =     []
												current_key_name.append(_UpperCamelCase   )

												if (isinstance(_UpperCamelCase	,     nn.Linear   ) or isinstance(_UpperCamelCase	,     _UpperCamelCase   )) and name not in modules_to_not_convert:
																		# Check if the current key is not in the `modules_to_not_convert`
																		if not any(key in '.'.join(_UpperCamelCase   ) for key in modules_to_not_convert   ):
																								with init_empty_weights():
																														if isinstance(_UpperCamelCase	,     _UpperCamelCase   ):
																																				snake_case   ,snake_case        =     module.weight.shape
																														else:
																																				snake_case        =     module.in_features
																																				snake_case        =     module.out_features

																														if quantization_config.quantization_method() == "llm_int8":
																																				snake_case        =     bnb.nn.LinearabitLt(
																																				    _UpperCamelCase	,     _UpperCamelCase	,     module.bias is not None	,     has_fpaa_weights=quantization_config.llm_inta_has_fpaa_weight	,     threshold=quantization_config.llm_inta_threshold	,     )
																																				snake_case        =     True
																														else:
																																				if (
																																				    quantization_config.llm_inta_skip_modules is not None
																																				    and name in quantization_config.llm_inta_skip_modules
																																				):
																																										pass
																																				else:
																																										snake_case        =     bnb.nn.Linearabit(
																																										    _UpperCamelCase	,     _UpperCamelCase	,     module.bias is not None	,     quantization_config.bnb_abit_compute_dtype	,     compress_statistics=quantization_config.bnb_abit_use_double_quant	,     quant_type=quantization_config.bnb_abit_quant_type	,     )
																																										snake_case        =     True
                    # Store the module class in case we need to transpose the weight later
																														snake_case        =     type(_UpperCamelCase   )
																														# Force requires grad to False to avoid unexpected errors
																														model._modules[name].requires_grad_(_UpperCamelCase   )
												if len(list(module.children()   )   ) > 0:
																		snake_case   ,snake_case        =     _replace_with_bnb_linear(
																		    _UpperCamelCase	,     _UpperCamelCase	,     _UpperCamelCase	,     _UpperCamelCase	,     has_been_replaced=_UpperCamelCase	,     )
												# Remove the last key for recursion
												current_key_name.pop(-1   )
						return model, has_been_replaced





def 				lowerCAmelCase__      (     _UpperCamelCase    :			List[str]	,     _UpperCamelCase    :			str=None	,     _UpperCamelCase    :			List[Any]=None	,     _UpperCamelCase    :			Union[str, Any]=None   )   ->			Union[str, Any]:





						"""simple docstring"""






						snake_case        =     ['lm_head'] if modules_to_not_convert is None else modules_to_not_convert
						snake_case   ,snake_case        =     _replace_with_bnb_linear(
						    _UpperCamelCase	,     _UpperCamelCase	,     _UpperCamelCase	,     _UpperCamelCase   )

						if not has_been_replaced:
												logger.warning(
												    'You are loading your model in 8bit or 4bit but no linear modules were found in your model.'
												    ' Please double check your model architecture, or submit an issue on github if you think this is'
												    ' a bug.'   )

						return model





def 				lowerCAmelCase__      (     *_UpperCamelCase    :			Any	,     **_UpperCamelCase    :			int   )   ->			str:





						"""simple docstring"""






						warnings.warn(
						    '`replace_8bit_linear` will be deprecated in a future version, please use `replace_with_bnb_linear` instead'	,     _UpperCamelCase	,     )
						return replace_with_bnb_linear(*_UpperCamelCase	,     **_UpperCamelCase   )





def 				lowerCAmelCase__      (     *_UpperCamelCase    :			Optional[int]	,     **_UpperCamelCase    :			Dict   )   ->			Tuple:





						"""simple docstring"""






						warnings.warn(
						    '`set_module_8bit_tensor_to_device` will be deprecated in a future version, please use `set_module_quantized_tensor_to_device` instead'	,     _UpperCamelCase	,     )
						return set_module_quantized_tensor_to_device(*_UpperCamelCase	,     **_UpperCamelCase   )





def 				lowerCAmelCase__      (     _UpperCamelCase    :			List[Any]   )   ->			Dict:





						"""simple docstring"""






						snake_case        =     deepcopy(_UpperCamelCase   )  # this has 0 cost since it is done inside `init_empty_weights` context manager`
						tied_model.tie_weights()

						snake_case        =     find_tied_parameters(_UpperCamelCase   )
						# For compatibility with Accelerate < 0.18
						if isinstance(_UpperCamelCase	,     _UpperCamelCase   ):
												snake_case        =     sum(list(tied_params.values()   )	,     []   ) + list(tied_params.keys()   )
						else:
												snake_case        =     sum(_UpperCamelCase	,     []   )
						snake_case        =     len(_UpperCamelCase   ) > 0

						# Check if it is a base model
						snake_case        =     not hasattr(_UpperCamelCase	,     model.base_model_prefix   )

						# Ignore this for base models (BertModel, GPT2Model, etc.)
						if (not has_tied_params) and is_base_model:
												return []

						# otherwise they have an attached head
						snake_case        =     list(model.named_children()   )
						snake_case        =     [list_modules[-1][0]]

						# add last module together with tied weights
						snake_case        =     set(_UpperCamelCase   ) - set(_UpperCamelCase   )
						snake_case        =     list(set(_UpperCamelCase   )   ) + list(_UpperCamelCase   )

						# remove ".weight" from the keys
						snake_case        =     ['.weight', '.bias']
						snake_case        =     []
						for name in list_untouched:
												for name_to_remove in names_to_remove:
																		if name_to_remove in name:
																								snake_case        =     name.replace(_UpperCamelCase	,     ''   )
												filtered_module_names.append(_UpperCamelCase   )

						return filtered_module_names



"""simple docstring"""
import pickle
import unittest

import torch

from accelerate import Accelerator
from accelerate.state import AcceleratorState
from accelerate.test_utils import require_cpu



@require_cpu
class 					lowerCAmelCase_      (     unittest.TestCase   ):



				"""simple docstring"""

				def 						snake_case	(			self      ):






										"""simple docstring"""

										snake_case        =     torch.nn.Linear(10						,      10      )
										snake_case        =     torch.optim.SGD(model.parameters()						,      0.1      )
										snake_case        =     Accelerator()
										snake_case        =     accelerator.prepare(lowerCAmelCase      )
										try:
																pickle.loads(pickle.dumps(lowerCAmelCase      )      )
										except Exception as e:
																self.fail(F"""Accelerated optimizer pickling failed with {e}"""      )
										AcceleratorState._reset_state()


