
import inspect
import unittest

import torch
import torch.nn as nn

from accelerate.hooks import (
    AlignDevicesHook,
    ModelHook,
    SequentialHook,
    add_hook_to_module,
    attach_align_device_hook,
    remove_hook_from_module,
    remove_hook_from_submodules,
)
from accelerate.test_utils import require_multi_gpu

class __snake_case		(				nn.Module					):
    def __init__(  self				):



           '''simple docstring'''







           super().__init__()
           lowercase							:					Optional[Any]	     =				nn.Linear(3		,4				)
           lowercase							:					Optional[int]	     =				nn.BatchNormad(4				)
           lowercase							:					Tuple	     =				nn.Linear(4		,5				)
    def 				_SCREAMING_SNAKE_CASE	(  self		,snake_case				):



           '''simple docstring'''







           return self.lineara(self.batchnorm(self.lineara(snake_case				)				)				)






class __snake_case		(				lowerCAmelCase					):
    def 				_SCREAMING_SNAKE_CASE	(  self		,snake_case		,*snake_case		,**snake_case				):



           '''simple docstring'''







           return (args[0] + 1,) + args[1:], kwargs






class __snake_case		(				lowerCAmelCase					):
    def 				_SCREAMING_SNAKE_CASE	(  self		,snake_case		,snake_case				):



           '''simple docstring'''







           return output + 1






class __snake_case		(				unittest.TestCase					):
    def 				_SCREAMING_SNAKE_CASE	(  self				):



           '''simple docstring'''







           lowercase							:					Any	     =				ModelForTest()
           lowercase							:					Any	     =				ModelHook()

           add_hook_to_module(snake_case		,snake_case				)
           self.assertEqual(test_model._hf_hook		,snake_case				)
           self.assertTrue(hasattr(snake_case		,"""_old_forward"""				)				)

           # Check adding the hook did not change the name or the signature
           self.assertEqual(test_model.forward.__name__		,"""forward"""				)
           self.assertListEqual(list(inspect.signature(test_model.forward				).parameters				)		,["""x"""]				)

           remove_hook_from_module(snake_case				)
           self.assertFalse(hasattr(snake_case		,"""_hf_hook"""				)				)
           self.assertFalse(hasattr(snake_case		,"""_old_forward"""				)				)
    def 				_SCREAMING_SNAKE_CASE	(  self				):



           '''simple docstring'''







           lowercase							:					Any	     =				ModelForTest()
           lowercase							:					List[str]	     =				ModelHook()

           add_hook_to_module(snake_case		,snake_case				)
           add_hook_to_module(snake_case		,snake_case		,append=snake_case				)

           self.assertEqual(isinstance(test_model._hf_hook		,snake_case				)		,snake_case				)
           self.assertEqual(len(test_model._hf_hook.hooks				)		,2				)
           self.assertTrue(hasattr(snake_case		,"""_old_forward"""				)				)

           # Check adding the hook did not change the name or the signature
           self.assertEqual(test_model.forward.__name__		,"""forward"""				)
           self.assertListEqual(list(inspect.signature(test_model.forward				).parameters				)		,["""x"""]				)

           remove_hook_from_module(snake_case				)
           self.assertFalse(hasattr(snake_case		,"""_hf_hook"""				)				)
           self.assertFalse(hasattr(snake_case		,"""_old_forward"""				)				)
    def 				_SCREAMING_SNAKE_CASE	(  self				):



           '''simple docstring'''







           lowercase							:					Dict	     =				ModelForTest()
           lowercase							:					Dict	     =				torch.randn(2		,3				)
           lowercase							:					List[Any]	     =				test_model(x + 1				)
           lowercase							:					Any	     =				test_model(x + 2				)

           lowercase							:					Optional[Any]	     =				PreForwardHook()
           add_hook_to_module(snake_case		,snake_case				)
           lowercase							:					Optional[int]	     =				test_model(snake_case				)
           self.assertTrue(torch.allclose(snake_case		,snake_case		,atol=1e-5				)				)

           # Attaching a hook to a model when it already has one replaces, does not chain
           lowercase							:					Optional[Any]	     =				PreForwardHook()
           add_hook_to_module(snake_case		,snake_case				)
           lowercase							:					Optional[Any]	     =				test_model(snake_case				)
           self.assertTrue(torch.allclose(snake_case		,snake_case		,atol=1e-5				)				)

           # You need to use the sequential hook to chain two or more hooks
           lowercase							:					Union[str, Any]	     =				SequentialHook(PreForwardHook()		,PreForwardHook()				)
           add_hook_to_module(snake_case		,snake_case				)

           lowercase							:					List[str]	     =				test_model(snake_case				)
           assert torch.allclose(snake_case		,snake_case		,atol=1e-5				)
    def 				_SCREAMING_SNAKE_CASE	(  self				):



           '''simple docstring'''







           lowercase							:					Optional[Any]	     =				ModelForTest()
           lowercase							:					Dict	     =				torch.randn(2		,3				)
           lowercase							:					Optional[Any]	     =				test_model(snake_case				)

           lowercase							:					Optional[Any]	     =				PostForwardHook()
           add_hook_to_module(snake_case		,snake_case				)
           lowercase							:					List[Any]	     =				test_model(snake_case				)
           self.assertTrue(torch.allclose(snake_case		,output + 1		,atol=1e-5				)				)

           # Attaching a hook to a model when it already has one replaces, does not chain
           lowercase							:					Any	     =				PostForwardHook()
           add_hook_to_module(snake_case		,snake_case				)
           lowercase							:					List[str]	     =				test_model(snake_case				)
           self.assertTrue(torch.allclose(snake_case		,output + 1		,atol=1e-5				)				)

           # You need to use the sequential hook to chain two or more hooks
           lowercase							:					Dict	     =				SequentialHook(PostForwardHook()		,PostForwardHook()				)
           add_hook_to_module(snake_case		,snake_case				)

           lowercase							:					List[Any]	     =				test_model(snake_case				)
           assert torch.allclose(snake_case		,output + 2		,atol=1e-5				)
    def 				_SCREAMING_SNAKE_CASE	(  self				):



           '''simple docstring'''







           lowercase							:					int	     =				ModelForTest()
           lowercase							:					Any	     =				torch.randn(2		,3				)
           lowercase							:					List[Any]	     =				test_model(snake_case				)

           lowercase							:					Union[str, Any]	     =				PostForwardHook()
           add_hook_to_module(snake_case		,snake_case				)
           lowercase							:					Any	     =				test_model(snake_case				)
           self.assertTrue(torch.allclose(snake_case		,output + 1				)				)
           self.assertTrue(outputa.requires_grad				)

           lowercase							:					Dict	     =				True
           lowercase							:					List[str]	     =				test_model(snake_case				)
           self.assertFalse(outputa.requires_grad				)
    @require_multi_gpu
    def 				_SCREAMING_SNAKE_CASE	(  self				):



           '''simple docstring'''







           lowercase							:					Optional[Any]	     =				ModelForTest()
           # Everything is on CPU
           self.assertEqual(model.lineara.weight.device		,torch.device("""cpu"""				)				)
           self.assertEqual(model.batchnorm.weight.device		,torch.device("""cpu"""				)				)
           self.assertEqual(model.lineara.weight.device		,torch.device("""cpu"""				)				)

           # This will move each submodule on different devices
           add_hook_to_module(model.lineara		,AlignDevicesHook(execution_device=0				)				)
           add_hook_to_module(model.batchnorm		,AlignDevicesHook(execution_device=0				)				)
           add_hook_to_module(model.lineara		,AlignDevicesHook(execution_device=1				)				)

           self.assertEqual(model.lineara.weight.device		,torch.device(0				)				)
           self.assertEqual(model.batchnorm.weight.device		,torch.device(0				)				)
           self.assertEqual(model.batchnorm.running_mean.device		,torch.device(0				)				)
           self.assertEqual(model.lineara.weight.device		,torch.device(1				)				)

           # We can still make a forward pass. The input does not need to be on any particular device
           lowercase							:					Optional[int]	     =				torch.randn(2		,3				)
           lowercase							:					str	     =				model(snake_case				)
           self.assertEqual(output.device		,torch.device(1				)				)

           # We can add a general hook to put back output on same device as input.
           add_hook_to_module(snake_case		,AlignDevicesHook(io_same_device=snake_case				)				)
           lowercase							:					Any	     =				torch.randn(2		,3				).to(0				)
           lowercase							:					str	     =				model(snake_case				)
           self.assertEqual(output.device		,torch.device(0				)				)
    def 				_SCREAMING_SNAKE_CASE	(  self				):



           '''simple docstring'''







           lowercase							:					List[str]	     =				ModelForTest()

           # Everything is on CPU
           self.assertEqual(model.lineara.weight.device		,torch.device("""cpu"""				)				)
           self.assertEqual(model.batchnorm.weight.device		,torch.device("""cpu"""				)				)
           self.assertEqual(model.lineara.weight.device		,torch.device("""cpu"""				)				)

           # This will move each submodule on different devices
           lowercase							:					Union[str, Any]	     =				{"""execution_device""": 0 if torch.cuda.is_available() else """cpu""", """offload""": True}

           add_hook_to_module(model.lineara		,AlignDevicesHook(**snake_case				)				)
           add_hook_to_module(model.batchnorm		,AlignDevicesHook(**snake_case				)				)
           add_hook_to_module(model.lineara		,AlignDevicesHook(**snake_case				)				)

           # Parameters have been offloaded, so on the meta device
           self.assertEqual(model.lineara.weight.device		,torch.device("""meta"""				)				)
           self.assertEqual(model.batchnorm.weight.device		,torch.device("""meta"""				)				)
           self.assertEqual(model.lineara.weight.device		,torch.device("""meta"""				)				)
           # Buffers are not included in the offload by default, so are on the execution device
           lowercase							:					Optional[Any]	     =				torch.device(hook_kwargs["""execution_device"""]				)
           self.assertEqual(model.batchnorm.running_mean.device		,snake_case				)

           lowercase							:					int	     =				torch.randn(2		,3				)
           lowercase							:					Tuple	     =				model(snake_case				)
           self.assertEqual(output.device		,snake_case				)

           # Removing hooks loads back the weights in the model.
           remove_hook_from_module(model.lineara				)
           remove_hook_from_module(model.batchnorm				)
           remove_hook_from_module(model.lineara				)
           self.assertEqual(model.lineara.weight.device		,torch.device("""cpu"""				)				)
           self.assertEqual(model.batchnorm.weight.device		,torch.device("""cpu"""				)				)
           self.assertEqual(model.lineara.weight.device		,torch.device("""cpu"""				)				)

           # Now test with buffers included in the offload
           lowercase							:					Dict	     =				{
               """execution_device""": 0 if torch.cuda.is_available() else """cpu""",
               """offload""": True,
               """offload_buffers""": True,
           }

           add_hook_to_module(model.lineara		,AlignDevicesHook(**snake_case				)				)
           add_hook_to_module(model.batchnorm		,AlignDevicesHook(**snake_case				)				)
           add_hook_to_module(model.lineara		,AlignDevicesHook(**snake_case				)				)

           # Parameters have been offloaded, so on the meta device, buffers included
           self.assertEqual(model.lineara.weight.device		,torch.device("""meta"""				)				)
           self.assertEqual(model.batchnorm.weight.device		,torch.device("""meta"""				)				)
           self.assertEqual(model.lineara.weight.device		,torch.device("""meta"""				)				)
           self.assertEqual(model.batchnorm.running_mean.device		,torch.device("""meta"""				)				)

           lowercase							:					str	     =				torch.randn(2		,3				)
           lowercase							:					Dict	     =				model(snake_case				)
           self.assertEqual(output.device		,snake_case				)

           # Removing hooks loads back the weights in the model.
           remove_hook_from_module(model.lineara				)
           remove_hook_from_module(model.batchnorm				)
           remove_hook_from_module(model.lineara				)
           self.assertEqual(model.lineara.weight.device		,torch.device("""cpu"""				)				)
           self.assertEqual(model.batchnorm.weight.device		,torch.device("""cpu"""				)				)
           self.assertEqual(model.lineara.weight.device		,torch.device("""cpu"""				)				)
    def 				_SCREAMING_SNAKE_CASE	(  self				):



           '''simple docstring'''







           lowercase							:					Optional[Any]	     =				ModelForTest()

           # Everything is on CPU
           self.assertEqual(model.lineara.weight.device		,torch.device("""cpu"""				)				)
           self.assertEqual(model.batchnorm.weight.device		,torch.device("""cpu"""				)				)
           self.assertEqual(model.lineara.weight.device		,torch.device("""cpu"""				)				)

           # This will move each submodule on different devices
           lowercase							:					List[str]	     =				0 if torch.cuda.is_available() else """cpu"""
           attach_align_device_hook(snake_case		,execution_device=snake_case		,offload=snake_case				)

           # Parameters have been offloaded, so on the meta device
           self.assertEqual(model.lineara.weight.device		,torch.device("""meta"""				)				)
           self.assertEqual(model.batchnorm.weight.device		,torch.device("""meta"""				)				)
           self.assertEqual(model.lineara.weight.device		,torch.device("""meta"""				)				)
           # Buffers are not included in the offload by default, so are on the execution device
           lowercase							:					List[str]	     =				torch.device(snake_case				)
           self.assertEqual(model.batchnorm.running_mean.device		,snake_case				)

           lowercase							:					Union[str, Any]	     =				torch.randn(2		,3				)
           lowercase							:					Optional[Any]	     =				model(snake_case				)
           self.assertEqual(output.device		,snake_case				)

           # Removing hooks loads back the weights in the model.
           remove_hook_from_submodules(snake_case				)
           self.assertEqual(model.lineara.weight.device		,torch.device("""cpu"""				)				)
           self.assertEqual(model.batchnorm.weight.device		,torch.device("""cpu"""				)				)
           self.assertEqual(model.lineara.weight.device		,torch.device("""cpu"""				)				)

           # Now test with buffers included in the offload
           attach_align_device_hook(snake_case		,execution_device=snake_case		,offload=snake_case		,offload_buffers=snake_case				)

           # Parameters have been offloaded, so on the meta device, buffers included
           self.assertEqual(model.lineara.weight.device		,torch.device("""meta"""				)				)
           self.assertEqual(model.batchnorm.weight.device		,torch.device("""meta"""				)				)
           self.assertEqual(model.lineara.weight.device		,torch.device("""meta"""				)				)
           self.assertEqual(model.batchnorm.running_mean.device		,torch.device("""meta"""				)				)

           lowercase							:					str	     =				torch.randn(2		,3				)
           lowercase							:					Any	     =				model(snake_case				)
           self.assertEqual(output.device		,snake_case				)

           # Removing hooks loads back the weights in the model.
           remove_hook_from_submodules(snake_case				)
           self.assertEqual(model.lineara.weight.device		,torch.device("""cpu"""				)				)
           self.assertEqual(model.batchnorm.weight.device		,torch.device("""cpu"""				)				)
           self.assertEqual(model.lineara.weight.device		,torch.device("""cpu"""				)				)
    def 				_SCREAMING_SNAKE_CASE	(  self				):



           '''simple docstring'''







           lowercase							:					Dict	     =				ModelForTest()

           # Everything is on CPU
           self.assertEqual(model.lineara.weight.device		,torch.device("""cpu"""				)				)
           self.assertEqual(model.batchnorm.weight.device		,torch.device("""cpu"""				)				)
           self.assertEqual(model.lineara.weight.device		,torch.device("""cpu"""				)				)

           # This will move each submodule on different devices
           lowercase							:					Union[str, Any]	     =				0 if torch.cuda.is_available() else """cpu"""
           attach_align_device_hook(
               snake_case		,execution_device=snake_case		,offload=snake_case		,weights_map=model.state_dict()				)

           # Parameters have been offloaded, so on the meta device
           self.assertEqual(model.lineara.weight.device		,torch.device("""meta"""				)				)
           self.assertEqual(model.batchnorm.weight.device		,torch.device("""meta"""				)				)
           self.assertEqual(model.lineara.weight.device		,torch.device("""meta"""				)				)
           # Buffers are not included in the offload by default, so are on the execution device
           lowercase							:					Optional[int]	     =				torch.device(snake_case				)
           self.assertEqual(model.batchnorm.running_mean.device		,snake_case				)

           lowercase							:					str	     =				torch.randn(2		,3				)
           lowercase							:					Dict	     =				model(snake_case				)
           self.assertEqual(output.device		,snake_case				)

           # Removing hooks loads back the weights in the model.
           remove_hook_from_submodules(snake_case				)
           self.assertEqual(model.lineara.weight.device		,torch.device("""cpu"""				)				)
           self.assertEqual(model.batchnorm.weight.device		,torch.device("""cpu"""				)				)
           self.assertEqual(model.lineara.weight.device		,torch.device("""cpu"""				)				)

           # Now test with buffers included in the offload
           attach_align_device_hook(
               snake_case		,execution_device=snake_case		,offload=snake_case		,weights_map=model.state_dict()		,offload_buffers=snake_case		,)

           # Parameters have been offloaded, so on the meta device, buffers included
           self.assertEqual(model.lineara.weight.device		,torch.device("""meta"""				)				)
           self.assertEqual(model.batchnorm.weight.device		,torch.device("""meta"""				)				)
           self.assertEqual(model.lineara.weight.device		,torch.device("""meta"""				)				)
           self.assertEqual(model.batchnorm.running_mean.device		,torch.device("""meta"""				)				)

           lowercase							:					int	     =				torch.randn(2		,3				)
           lowercase							:					Optional[Any]	     =				model(snake_case				)
           self.assertEqual(output.device		,snake_case				)

           # Removing hooks loads back the weights in the model.
           remove_hook_from_submodules(snake_case				)
           self.assertEqual(model.lineara.weight.device		,torch.device("""cpu"""				)				)
           self.assertEqual(model.batchnorm.weight.device		,torch.device("""cpu"""				)				)
           self.assertEqual(model.lineara.weight.device		,torch.device("""cpu"""				)				)


from collections.abc import Generator







def 						_snake_case(  )			->   Generator[int, None, None]:
       lowercase     ,      lowercase							:					List[str]	     =				0, 1
       while True:
              lowercase     ,      lowercase							:					Optional[int]	     =				b, a + b
              yield b







def 						_snake_case(  SCREAMING_SNAKE_CASE__ = 1_000    )			->   int:
       lowercase							:					List[Any]	     =				1
       lowercase							:					Tuple	     =				fibonacci_generator()
       while len(str(next(SCREAMING_SNAKE_CASE__    )    )    ) < n:
              answer += 1
       return answer + 1


if __name__ == "__main__":
  print(solution(int(str(input()).strip())))
