o
    Ne3                    @   s  d dl mZ d dlZd dlZd dlZd dlZd dlmZ d dlZd dl	Z	d dl
mZmZmZmZ d dlZd dlZd dlmZmZ d dlmZmZmZ d dlmZ d dlmZmZ d d	lmZmZ d d
l m!Z! d dl"m#Z#m$Z$ d dl%m&Z&m'Z' d dl(m)Z)m*Z*m+Z+ d dl,m-Z-m.Z.m/Z/m0Z0m1Z1 d dl2m3Z3 d dl4m5Z5m6Z6 d dl7m8Z8m9Z9m:Z:m;Z;m<Z<m=Z= d dl7m>Z>m?Z?m@Z@ d dl7mAZAmBZB d dlCmDZD g dZEdd ZFdKddZGdKddZHdd ZIeDeIZJdd  ZK				!dLd"d#ZLdMd$d%ZMG d&d' d'eNZOd(d) ZPd*d+ ZQd,d- ZRdNd.d/ZSd0d1 ZTe	U aVg aWG d2d3 d3eNZXd4d5 ZYd6d7 ZZd8d9 Z[eDd:d; Z\d<ed=eeeef  fd>d?Z]e\edMd@dAZ^eAdBdC Z_eA	D	E	FdOdGdHZ`G dIdJ dJeNZadS )P    )print_functionN)OrderedDict)TextTupleAnyList)coredygraph)BuildStrategyCompiledProgramExecutionStrategy)
check_type)flattenpack_sequence_as)program_desc_tracing_guardswitch_to_static_graph)logging_utils)ConversionOptionsCONVERSION_OPTIONS)set_code_levelset_verbosity)ProgramTranslatorStaticFunctionunwrap_decorators)TranslatedLayerINFER_MODEL_SUFFIXINFER_PARAMS_SUFFIXINFER_PARAMS_INFO_SUFFIXINFER_PROPERTY_SUFFIX)Layer)Executorscope_guard)Block	ParamBaseProgramVariable	ParameterEagerParamBase)_current_expected_place_dygraph_guard_dygraph_tracer)dygraph_only_non_static_mode)wrap_decorator)TracedLayerdeclarativedygraph_to_static_funcr   r   saveloadnot_to_staticc                 C   s&   t  }| |_t|dg|_|  |S Nr   )r$   descr"   blocksZ_sync_with_cpp)program_descprogram r9   HD:\Projects\ConvertPro\env\Lib\site-packages\paddle/fluid/dygraph/jit.pycreate_program_from_desc4   s
   r;   inputsc                 C   sT   t | tr||  d S t | ttfr | D ]}t||| qd S td|t| )NzpThe type of 'each element of {}' in fluid.dygraph.jit.TracedLayer.trace must be fluid.Variable, but received {}.)	
isinstancer%   appendlisttuple_extract_vars	TypeErrorformattype)r<   result_listerr_tagvarr9   r9   r:   rA   <   s   
rA   c                 C   s   g }t | || |S N)rA   )r<   rF   rE   r9   r9   r:   extract_varsH   s   rI   c                    s    fdd}|S )aj  
    Converts imperative dygraph APIs into declarative function APIs. Decorator
    @dygraph_to_static_func only converts imperative dygraph APIs into
    declarative net-building APIs, which means it doesn't return immediate
    digital result as imperative mode. Users should handle Program and Executor
    by themselves.

    Note:
    This decorator is NOT our recommended way to transform imperative function
    to declarative function. We will remove this decorator after we finalize
    cleaning up code.

    Args:
        dygraph_func (callable): callable imperative function.

    Returns:
        Callable: converting imperative dygraph APIs into declarative
        net-building APIs.

    Examples:
        .. code-block:: python

          import paddle.fluid as fluid
          import numpy as np
          from paddle.fluid.dygraph.jit import dygraph_to_static_func

          @dygraph_to_static_func
          def func(x):
              if paddle.mean(x) < 0:
                  x_v = x - 1
              else:
                  x_v = x + 1

               return x_v

          x = fluid.layers.fill_constant(shape=[3, 3], value=0, dtype='float64')

          x_v = func(x)
          exe = fluid.Executor(fluid.CPUPlace())
          out = exe.run(fetch_list=[x_v])
          print(out[0])
          # [[1. 1. 1.]
          #  [1. 1. 1.]
          #  [1. 1. 1.]]

    c                     sB   t  }t s	|jstd  | i |S | }|| i |S )NzThe decorator 'dygraph_to_static_func' doesn't work in dygraph mode or set ProgramTranslator.enable to False. We will just return dygraph output.)r   r,   enable_to_staticr   warnZget_func)argskwargsZprogram_translatorstatic_funcdygraph_funcr9   r:   __impl__   s   
z*_dygraph_to_static_func_.<locals>.__impl__r9   )rP   rQ   r9   rO   r:   _dygraph_to_static_func_N   s   1rR   c                 C   s6   d}| j |_ ||_| |_| j|_t| dr| j|_|S )z
    Copies some necessary attributes from original function into decorated function.

    Args:
        original_func(callable): the original decorated function.
        decorated_obj(StaticFunction): the target decorated StaticFunction object.
    r/   
__module__)__name__Z_decorator_name__wrapped____doc__hasattrrS   )original_funcdecorated_objZdecorator_namer9   r9   r:   copy_decorator_attrs   s   
rZ   Fc                    s    fdd} pt   t t stdt j| durCt| tr?t| jtr7| j	j}t
d| || j| _| S || S |S )a  
    Converts imperative dygraph APIs into declarative function APIs. Decorator
    @declarative handles the Program and Executor of static mode and returns
    the result as dygraph Tensor(s). Users could use the returned dygraph
    Tensor(s) to do imperative training, inference, or other operations. If the
    decorated function calls other imperative function, the called one will be
    converted into declarative function as well.

    Args:
        function (callable): callable imperative function.
        input_spec(list[InputSpec]|tuple[InputSpec]): list/tuple of InputSpec to specific the shape/dtype/name
            information of each input Tensor.
        build_strategy(BuildStrategy|None): This argument is used to compile the
            converted program with the specified options, such as operators' fusion
            in the computational graph and memory optimization during the execution
            of the computational graph. For more information about build_strategy,
            please refer to :code:`paddle.static.BuildStrategy`. The default is None.
        property(bool, Optional): whether the fucntion is python property. The default is False.


    Returns:
        Tensor(s): containing the numerical result.

    Examples:
        .. code-block:: python

            import paddle
            from paddle.jit import to_static

            @to_static
            def func(x):
                if paddle.mean(x) < 0:
                    x_v = x - 1
                else:
                    x_v = x + 1
                return x_v

            x = paddle.ones([1, 2], dtype='float32')
            x_v = func(x)
            print(x_v) # [[2. 2.]]

    c                    s(   t | \}} t| t|  dd}|S )zK
        Decorates a python function into a StaticFunction object.
        )function
input_specbuild_strategyproperty)rX   rY   )r   rZ   r   )Zpython_func_Zstatic_layerr]   r\   r^   r9   r:   	decorated   s   zdeclarative.<locals>.decoratedzURequired type(build_strategy) shall be `paddle.static.BuildStrategy`, but received {}Nzb`{}.forward` has already been decorated somewhere. It will be redecorated to replace previous one.)r
   r=   rB   rC   rD   rT   r   forwardr   	__class__r   rK   )r[   r\   r]   r^   ra   
class_namer9   r`   r:   r/      s&   /


r/   c                 C   s&   | du rt S tdd}t| t| | S )a  
    A Decorator to suppresses the convertion of a function.

    Args:
        func(callable): The function to decorate.

    Returns:
        callable: A function which won't be converted in Dynamic-to-Static.

    Examples:
        .. code-block:: python

            import paddle

            @paddle.jit.not_to_static
            def func_not_to_static(x):
                res = x - 1
                return res

            @paddle.jit.to_static
            def func(x):
                if paddle.mean(x) < 0:
                    out = func_not_to_static(x)
                else:
                    out = x + 1
                return out

            x = paddle.ones([1, 2], dtype='float32')
            out = func(x)
            print(out) # [[2. 2.]]
    NT)Znot_convert)r3   r   setattrr   )funcoptionsr9   r9   r:   r3      s
    
r3   c                   @   s|   e Zd Zdd Zedd Zejdd Zedd Zejdd Zed	d
 Zejdd
 Zedd Z	e	jdd Z	dS )_SaveLoadConfigc                 C   s:   d | _ d | _d | _d| _d| _d| _d| _d| _d| _d S )NFT)	_output_spec_model_filename_params_filenameZ_separate_params_keep_name_table_export_for_deployment_program_only	with_hookcombine_paramsselfr9   r9   r:   __init__%  s   
z_SaveLoadConfig.__init__c                 C      | j S rH   )ri   rq   r9   r9   r:   output_spec<     z_SaveLoadConfig.output_specc                 C   s0   |d u rd S t |tstdtt || _d S )NzIThe config `output_spec` should be 'list', but received input type is %s.)r=   r?   rB   rD   inputr   VarBaseri   )rr   specrG   r9   r9   r:   ru   @  s   

c                 C   rt   rH   )rj   rq   r9   r9   r:   model_filenameO  rv   z_SaveLoadConfig.model_filenamec                 C   F   |d u rd S t |tjstdt| t|dkrtd|| _d S )NzKThe config `model_filename` should be str, but received input's type is %s.r   z,The config `model_filename` is empty string.)r=   sixstring_typesrB   rD   len
ValueErrorrj   rr   filenamer9   r9   r:   rz   S     
c                 C   rt   rH   )rk   rq   r9   r9   r:   params_filename_  rv   z_SaveLoadConfig.params_filenamec                 C   r{   )NzLThe config `params_filename` should be str, but received input's type is %s.r   z-The config `params_filename` is empty string.)r=   r|   r}   rB   rD   r~   r   rk   r   r9   r9   r:   r   c  r   c                 C   rt   rH   )rl   rq   r9   r9   r:   keep_name_tableo  rv   z_SaveLoadConfig.keep_name_tablec                 C   s0   |d u rd S t |tstdt| || _d S )NzSThe config `keep_name_table` should be bool value, but received input's type is %s.)r=   boolrB   rD   rl   )rr   valuer9   r9   r:   r   s  s   

N)
rT   rS   __qualname__rs   r^   ru   setterrz   r   r   r9   r9   r9   r:   rh   #  s$    






rh   c                 C   sv   g d}| D ]}||vrt d| qt }| dd |_| dd|_| dd|_| dd|_| d	d|_|S )
N)ru   ro   rp   
clip_extraskip_forwardzAThe additional config (%s) of `paddle.jit.save` is not supported.ru   ro   Frp   r   Tr   )r   rh   getru   ro   rp   r   r   configsZsupported_configskeyZinner_configr9   r9   r:   _parse_save_configs~  s    r   c                 C   sL   ddg}| D ]}||vrt d| qt }| dd |_| dd |_|S )Nrz   r   zAThe additional config (%s) of `paddle.jit.load` is not supported.)r   rh   r   rz   r   r   r9   r9   r:   _parse_load_config  s   r   c                 C   s   d}d}g }dd t | D }|d u r|S dd |D }t|t|krI|}|D ]}|jd u r7t||  q(|j|vrEt||j  q(	 q(|S |D ]}|jd u rXt|| |j|vrdt||j ||j qK|S )NzThe %s's name is None. When using jit.save, please set InputSepc's name in to_static(input_spec=[]) and jit.save(input_spec=[]) and make sure they are consistent.zThe tensor `%s` does not exists. Please make sure the name of InputSpec or example Tensor in input_spec is the same as the name of InputSpec in `to_static` decorated on the Layer.forward method.c                 S   s   g | ]
}t |tr|jqS r9   )r=   r%   name).0rG   r9   r9   r:   
<listcomp>  s
    
z(_get_input_var_names.<locals>.<listcomp>c                 S   s   g | ]}t |tjjr|qS r9   )r=   paddlestatic	InputSpec)r   ry   r9   r9   r:   r     s    )r   r~   r   warningsrK   r   r>   )r<   r\   Zname_none_errorname_no_exists_errorrE   input_var_namesry   r9   r9   r:   _get_input_var_names  s6   



r   c                 C   s   d}|r
|r
t dg }t }t| D ]}t|tr|||j< q|d u r,t| }|S |d urRt|t|krRt| }|D ]}|j|vrOt	
||j  q@|S |D ]}|j|vrbt||j |||j  qT|S )NzThe tensor `%s` does not exists. Please make sure the name of example Tensor in configs.output_spec is the output tensor of Layer.forward method.z`Currently not support specify output_spec while founding pre/post hooks in your outermost layer.)RuntimeErrorr   r   r=   r%   r   r?   valuesr~   r   rK   r   r>   )outputsru   ro   r   rE   Zoutput_vars_dictrG   r9   r9   r:   _get_output_vars  s4   



r   c                 C   s   | t  }tj|}tj| }|r|rtd| | f |s&|s&td|  |rVtj| }tj| }|jd ur>t	
d |t  |_|jd urMt	
d |t |_||fS | }||fS )NzThe %s.pdmodel and %s directory exist at the same time, don't know which one to load, please make sure that the specified target of ``path`` is unique.zThe ``path`` (%s) to load model not exists. Please make sure that *.pdmodel exists or don't using ``skip_forward=True`` to jit.save.zqWhen loading the result saved with the specified file prefix, the ``model_filename`` config does not take effect.zrWhen loading the result saved with the specified file prefix, the ``params_filename`` config does not take effect.)r   ospathexistsisdirr   basenamedirnamerz   r   rK   r   r   )r   configZprefix_format_pathZprefix_format_existZdirectory_format_existfile_prefix
model_pathr9   r9   r:   _build_load_path_and_config  s:   



r   c                   @   s    e Zd ZdZdd Zdd ZdS )HookRemoveHelperz5 A HookRemoveHelper that can be used to remove hook. c                 C   s
   || _ d S rH   )_hook)rr   hookr9   r9   r:   rs   1  s   
zHookRemoveHelper.__init__c                 C   s   t | j d S rH   )_remove_save_pre_hookr   rq   r9   r9   r:   remove4  s   zHookRemoveHelper.removeN)rT   rS   r   rV   rs   r   r9   r9   r9   r:   r   .  s    r   c                 C   s*   t   | tvrt|  t   t| S )a  
    Register a save pre-hook for `paddle.jit.save`.
    This hook will be executed before `save` function has been invoked.

    hook(layer, input_spec, configs) -> None
    - layer (Layer|function): This argument is corresponding to `layer` in `paddle.jit.save`.
    - input_spec (list or tuple[InputSpec|Tensor|Python built-in variable]): This argument is corresponding to `input_spec` in `paddle.jit.save`.
    - configs (dict): This argument is corresponding to `configs` in `paddle.jit.save`.

    Args:
        hook(function): a function registered as a save pre-hook

    Returns:
        HookRemoveHelper: a HookRemoveHelper object that can be used to remove the added hook by calling `hook_remove_helper.remove()`.

    Examples:
        .. code-block:: python

            import numpy as np
            import paddle

            IMAGE_SIZE = 256
            CLASS_NUM = 10

            class LinearNet(paddle.nn.Layer):
                def __init__(self):
                    super(LinearNet, self).__init__()
                    self._linear = paddle.nn.Linear(IMAGE_SIZE, CLASS_NUM)

                def forward(self, x):
                    return self._linear(x)

            saving_count = 0
            def save_pre_hook(layer, input_spec, configs):
                global saving_count
                saving_count += 1

            remove_handler = paddle.jit.register_save_pre_hook(save_pre_hook)

            layer = LinearNet()
            paddle.jit.save(layer, "/tmp", [paddle.static.InputSpec(shape=[-1, IMAGE_SIZE])])
            # saving_count == 1

            remove_handler.remove()
            paddle.jit.save(layer, "/tmp", [paddle.static.InputSpec(shape=[-1, IMAGE_SIZE])])
            # saving_count == 1
    )_save_pre_hooks_lockacquire_save_pre_hooksr>   releaser   r   r9   r9   r:   _register_save_pre_hook8  s
   2
r   c                   C   s   t   t  t   d S rH   )r   r   r   clearr   r9   r9   r9   r:   _clear_save_pre_hooksq  s   r   c                 C   s&   t   | tv rt|  t   d S rH   )r   r   r   r   r   r   r9   r9   r:   r   y  s   
r   c                    s   d fdd	}|S )Nc                    s.   t D ]}|| || q | ||fi | d S rH   )r   )layerr   r\   r   r   rf   r9   r:   wrapper  s   z$_run_save_pre_hooks.<locals>.wrapperrH   r9   )rf   r   r9   r   r:   _run_save_pre_hooks  s   r   r   property_valsc                 C   sz   dd }t | d*}tjj }|D ]}|d |d }}|||| q||  W d   dS 1 s6w   Y  dS )zclass property serialization.

    Args:
        filename (Text): *.meta
        property_vals (List[Tuple): class property.
    c                 S   s   t |tr| || d S t |tr| || d S t |tr'| || d S t |ttfr[t |d tr=| 	|| d S t |d trL| 
|| d S t |d trY| || d S tdt| )Nr   zNote support val type: )r=   floatZ	set_floatintZset_intstrZ
set_stringr@   r?   Z
set_floatsZset_intsZset_stringsr   rD   )metar   valr9   r9   r:   set_property  s(   



z$_save_property.<locals>.set_propertywbr      N)openr   Z	frameworkr   PropertywriteZserialize_to_string)r   r   r   fr   itemr   r   r9   r9   r:   _save_property  s   "r   c           /      K   s  t  }|js
tdt| ts!t| s!t| ts!tdt	|  t| s+t| tr0t
d t| tjr:| j}n| }tj|}|dkrJtdtj|}|r]tj|s]t| d}|durt| trt|D ]}	t||	d}
t|
trd|	krtdt	| qlt|ttfstd	t	| g }t|D ]*}t|tjjr|| qt|tjtj j!t"fr|tjj#| q|| qt$|}|j%}|j&}|rd
|_'t( }t) }t| trt|}|j*s|j+rd
}n| g}i }g }d}|D ]}	t| trNt||	d}
t|
tr+|
j,r#|
 }||| j-j.d |	 f q|
j/||d}n]d|	krM|j0r5q|r=t1||}t2|j3|d}|j/|d}d}n;qt|	tri|	j,rc|	 }|||	f q|	/|}n|rqt1||}t2|	|d}|j4}|j5du rt
d6|  d}t|tr|7 }nt|	tr|	j5r|	j57 }|rt) }t) }t89|D ]\}}|||j:< |||j:< qt;< m |j=D ]a}|j	tj>j?j@kr|A B }|C|j:}|D| n|C|j:E }||j: A E }|F| |j:|vr*t) } |j:|v r||j: | d< |jG| d< t|tHtIfr%|jJ| d< | ||j:< qW d   n	1 s7w   Y  tK|jL|}!tM|jN|jO|}"ddlPmQ}# |}$d|	ks]t| tsf|tR }%|tS }&n|d |	 tR }%|d |	 tS }&tT| |#|$|!|"tUtV |jWX |%|&|jY|j'|jZd
 W d   n	1 sw   Y  |r|jWX }'|'[|!|"}'|'j\D ]	}(|]|(j^ qq|rt_|` dd d}g })|D ]
\}*}|)| q|tS }&tT| tjjatUtV |$ttbtjcjdje|)|&d W d   n	1 sw   Y  tjftjg|$|th }+ti|+| d},|dur1|jWj D ]
}|,t|tkO },q&t| ts:|,r|rtT|3 |tl }-tm|-d}.tnjo||.dd W d   n1 s_w   Y  W d   dS W d   dS 1 sxw   Y  dS dS dS )a2  
    Saves input Layer or function as ``paddle.jit.TranslatedLayer``
    format model, which can be used for inference or fine-tuning after loading.

    It will save the translated program and all related persistable
    variables of input Layer to given ``path`` .

    ``path`` is the prefix of saved objects, and the saved translated program file
    suffix is ``.pdmodel`` , the saved persistable variables file suffix is ``.pdiparams`` ,
    and here also saved some additional variable description information to a file,
    its suffix is ``.pdiparams.info``, these additional information is used in fine-tuning.

    The saved model can be loaded by follow APIs:
      - ``paddle.jit.load``
      - ``paddle.static.load_inference_model``
      - Other C++ inference APIs

    .. note::
        When using ``paddle.jit.save`` to save a function, parameters will not be saved. If you have to 
        save the parameter, please pass the Layer containing function and parameter to ``paddle.jit.save``.

    Args:
        layer (Layer|function): The Layer or function to be saved.
        path (str): The path prefix to save model. The format is ``dirname/file_prefix`` or ``file_prefix``.
        input_spec (list or tuple[InputSpec|Tensor|Python built-in variable], optional): Describes the input of the saved model's forward
            method, which can be described by InputSpec or example Tensor. Moreover, we support to specify non-tensor type argument,
            such as int, float, string, or list/dict of them.If None, all input variables of
            the original Layer's forward method would be the inputs of the saved model. Default None.
        **configs (dict, optional): Other save configuration options for compatibility. We do not
            recommend using these configurations, they may be removed in the future. If not necessary,
            DO NOT use them. Default None.
            The following options are currently supported:
            (1) output_spec (list[Tensor]): Selects the output targets of the saved model.
            By default, all return variables of original Layer's forward method are kept as the
            output of the saved model. If the provided ``output_spec`` list is not all output variables,
            the saved model will be pruned according to the given ``output_spec`` list.

    Returns:
        None

    Examples:
        .. code-block:: python

            # example 1: save layer
            import numpy as np
            import paddle
            import paddle.nn as nn
            import paddle.optimizer as opt

            BATCH_SIZE = 16
            BATCH_NUM = 4
            EPOCH_NUM = 4

            IMAGE_SIZE = 784
            CLASS_NUM = 10

            # define a random dataset
            class RandomDataset(paddle.io.Dataset):
                def __init__(self, num_samples):
                    self.num_samples = num_samples

                def __getitem__(self, idx):
                    image = np.random.random([IMAGE_SIZE]).astype('float32')
                    label = np.random.randint(0, CLASS_NUM - 1, (1, )).astype('int64')
                    return image, label

                def __len__(self):
                    return self.num_samples

            class LinearNet(nn.Layer):
                def __init__(self):
                    super(LinearNet, self).__init__()
                    self._linear = nn.Linear(IMAGE_SIZE, CLASS_NUM)

                @paddle.jit.to_static
                def forward(self, x):
                    return self._linear(x)

            def train(layer, loader, loss_fn, opt):
                for epoch_id in range(EPOCH_NUM):
                    for batch_id, (image, label) in enumerate(loader()):
                        out = layer(image)
                        loss = loss_fn(out, label)
                        loss.backward()
                        opt.step()
                        opt.clear_grad()
                        print("Epoch {} batch {}: loss = {}".format(
                            epoch_id, batch_id, np.mean(loss.numpy())))

            # 1. train & save model.

            # create network
            layer = LinearNet()
            loss_fn = nn.CrossEntropyLoss()
            adam = opt.Adam(learning_rate=0.001, parameters=layer.parameters())

            # create data loader
            dataset = RandomDataset(BATCH_NUM * BATCH_SIZE)
            loader = paddle.io.DataLoader(dataset,
                batch_size=BATCH_SIZE,
                shuffle=True,
                drop_last=True,
                num_workers=2)

            # train
            train(layer, loader, loss_fn, adam)

            # save
            path = "example_model/linear"
            paddle.jit.save(layer, path)

            # example 2: save function
            import paddle
            from paddle.static import InputSpec


            def save_function():
                @paddle.jit.to_static
                def fun(inputs):
                    return paddle.tanh(inputs)

                path = 'test_jit_save_load_function_1/func'
                inps = paddle.rand([3, 6])
                origin = fun(inps)

                paddle.jit.save(fun, path)
                load_func = paddle.jit.load(path)

                load_result = load_func(inps)
                print((load_result - origin).abs().max() < 1e-10)
                
            save_function()
    zPThe paddle.jit.save doesn't work when setting ProgramTranslator.enable to False.z\The input of paddle.jit.save should be 'Layer' or 'Function', but received input type is %s.a  What you save is a function, and `jit.save` will generate the name of the model file according to `path` you specify. When loading these files with `jit.load`, you get a `TranslatedLayer` whose inference result is the same as the inference result of the function you saved. The input path MUST be format of dirname/file_prefix [dirname\file_prefix in Windows system], but received file_prefix is empty string.Nrb   zIf there are static functions other than 'forward' that need to be saved, the input 'input_spec' should be None, but received the type of 'input_spec' is %s.zLThe input input_spec should be 'list', but received input_spec's type is %s.T.)ro   )r\   z`jit.save` will only save the `Program`, not the parameters. If you have to save the parameters, please make sure that {} is a member function of `paddle.nn.Layer` and the saved parameters are in `state_dict`structured_namestop_gradient	trainabler   save_inference_model)
r   feeded_var_namestarget_varsexecutormain_programrz   r   Zexport_for_deploymentZprogram_onlyr   c                 S   s   | d S r4   r9   )r   r9   r9   r:   <lambda>7  s    zsave.<locals>.<lambda>)r   )r   varsr   Fr      )protocol)pr   rJ   r   r=   r   inspect
isfunctionr   rB   rD   r   rK   r   ZDataParallelZ_layersr   r   r   r   r   r   makedirsdirgetattrr?   r@   r   r   r   r>   r   rx   eagerZTensorr%   Zfrom_tensorr   ro   rp   rn   ScopedictZ_forward_pre_hooksZ_forward_post_hooksZis_propertyrc   rT   Z#concrete_program_specify_input_specr   r   r/   rb   concrete_programZ_class_instancerC   Zto_static_state_dictr|   	iteritemsr   r	   guard
parametersZVarDescZVarTypeZVOCABr   Zget_map_tensorrG   Z	set_vocab
get_tensor_share_data_withr   r#   r'   r   r   r<   r   r   ru   paddle.fluid.ior   r   r   r!   r    r(   r   clonerm   r   Z_prune_with_inputr6   updater   sorteditemsZ	save_varsfilterZfluidioZis_persistablejoinnormpathr   r   Z	list_varsr&   r   r   pickledump)/r   r   r\   r   Zprog_translatorZinner_layerr   r   Zinner_input_specZ	attr_funcrN   rG   ro   rp   scopeZextra_var_infoZ	functionsZcombine_varsr   r   Zimmediate_valZstatic_forwardZstatic_functionZdygraph_state_dictZstate_names_dictZstate_var_dictr   Zparam_or_bufferZ
scr_tensorZtgt_varZparam_or_buffer_tensor
src_tensorZextra_info_dictr   Zoutput_varsr   r   rz   r   Zclone_main_programblockZordered_varsr   Zproperty_save_pathZcontain_parameterZextra_var_info_pathr   r9   r9   r:   r1     s   	












#	








 $r1   c                 K   s"   t |}t| |\}}t||S )a   
    :api_attr: imperative

    Load model saved by ``paddle.jit.save`` or ``paddle.static.save_inference_model`` or
    paddle 1.x API ``paddle.fluid.io.save_inference_model`` as ``paddle.jit.TranslatedLayer``,
    then performing inference or fine-tune training.

    .. note::
        If you load model saved by ``paddle.static.save_inference_model`` ,
        there will be the following limitations when using it in fine-tuning:
        1. Imperative mode do not support LoDTensor. All original model's feed targets or parametars that depend on LoD are temporarily unavailable.
        2. All saved model's feed targets need to be passed into TranslatedLayer's forward function.
        3. The variable's ``stop_gradient`` information is lost and can not be recovered.
        4. The parameter's ``trainable`` information is lost and can not be recovered.

    Args:
        path (str): The path prefix to load model. The format is ``dirname/file_prefix`` or ``file_prefix`` .
        **configs (dict, optional): Other load configuration options for compatibility. We do not
            recommend using these configurations, they may be removed in the future. If not necessary,
            DO NOT use them. Default None.
            The following options are currently supported:
            (1) model_filename (str): The inference model file name of the paddle 1.x
            ``save_inference_model`` save format. Default file name is :code:`__model__` .
            (2) params_filename (str): The persistable variables file name of the paddle 1.x
            ``save_inference_model`` save format. No default file name, save variables separately
            by default.


    Returns:
        TranslatedLayer: A Layer object can run saved translated model.

    Examples:
        1. Load model saved by ``paddle.jit.save`` then performing inference and fine-tune training.

        .. code-block:: python

            import numpy as np
            import paddle
            import paddle.nn as nn
            import paddle.optimizer as opt

            BATCH_SIZE = 16
            BATCH_NUM = 4
            EPOCH_NUM = 4

            IMAGE_SIZE = 784
            CLASS_NUM = 10

            # define a random dataset
            class RandomDataset(paddle.io.Dataset):
                def __init__(self, num_samples):
                    self.num_samples = num_samples

                def __getitem__(self, idx):
                    image = np.random.random([IMAGE_SIZE]).astype('float32')
                    label = np.random.randint(0, CLASS_NUM - 1, (1, )).astype('int64')
                    return image, label

                def __len__(self):
                    return self.num_samples

            class LinearNet(nn.Layer):
                def __init__(self):
                    super(LinearNet, self).__init__()
                    self._linear = nn.Linear(IMAGE_SIZE, CLASS_NUM)

                @paddle.jit.to_static
                def forward(self, x):
                    return self._linear(x)

            def train(layer, loader, loss_fn, opt):
                for epoch_id in range(EPOCH_NUM):
                    for batch_id, (image, label) in enumerate(loader()):
                        out = layer(image)
                        loss = loss_fn(out, label)
                        loss.backward()
                        opt.step()
                        opt.clear_grad()
                        print("Epoch {} batch {}: loss = {}".format(
                            epoch_id, batch_id, np.mean(loss.numpy())))

            # 1. train & save model.

            # create network
            layer = LinearNet()
            loss_fn = nn.CrossEntropyLoss()
            adam = opt.Adam(learning_rate=0.001, parameters=layer.parameters())

            # create data loader
            dataset = RandomDataset(BATCH_NUM * BATCH_SIZE)
            loader = paddle.io.DataLoader(dataset,
                batch_size=BATCH_SIZE,
                shuffle=True,
                drop_last=True,
                num_workers=2)

            # train
            train(layer, loader, loss_fn, adam)

            # save
            path = "example_model/linear"
            paddle.jit.save(layer, path)

            # 2. load model

            # load
            loaded_layer = paddle.jit.load(path)

            # inference
            loaded_layer.eval()
            x = paddle.randn([1, IMAGE_SIZE], 'float32')
            pred = loaded_layer(x)

            # fine-tune
            loaded_layer.train()
            adam = opt.Adam(learning_rate=0.001, parameters=loaded_layer.parameters())
            train(loaded_layer, loader, loss_fn, adam)


        2. Load model saved by ``paddle.fluid.io.save_inference_model`` then performing and fine-tune training.

        .. code-block:: python

            import numpy as np
            import paddle
            import paddle.static as static
            import paddle.nn as nn
            import paddle.optimizer as opt
            import paddle.nn.functional as F

            BATCH_SIZE = 16
            BATCH_NUM = 4
            EPOCH_NUM = 4

            IMAGE_SIZE = 784
            CLASS_NUM = 10

            # define a random dataset
            class RandomDataset(paddle.io.Dataset):
                def __init__(self, num_samples):
                    self.num_samples = num_samples

                def __getitem__(self, idx):
                    image = np.random.random([IMAGE_SIZE]).astype('float32')
                    label = np.random.randint(0, CLASS_NUM - 1, (1, )).astype('int64')
                    return image, label

                def __len__(self):
                    return self.num_samples

            paddle.enable_static()

            image = static.data(name='image', shape=[None, 784], dtype='float32')
            label = static.data(name='label', shape=[None, 1], dtype='int64')
            pred = static.nn.fc(x=image, size=10, activation='softmax')
            loss = F.cross_entropy(input=pred, label=label)
            avg_loss = paddle.mean(loss)

            optimizer = paddle.optimizer.SGD(learning_rate=0.001)
            optimizer.minimize(avg_loss)

            place = paddle.CPUPlace()
            exe = static.Executor(place)
            exe.run(static.default_startup_program())

            # create data loader
            dataset = RandomDataset(BATCH_NUM * BATCH_SIZE)
            loader = paddle.io.DataLoader(dataset,
                feed_list=[image, label],
                places=place,
                batch_size=BATCH_SIZE,
                shuffle=True,
                drop_last=True,
                return_list=False,
                num_workers=2)

            # 1. train and save inference model
            for data in loader():
                exe.run(
                    static.default_main_program(),
                    feed=data,
                    fetch_list=[avg_loss])

            model_path = "fc.example.model"
            paddle.fluid.io.save_inference_model(
                model_path, ["image"], [pred], exe)

            # 2. load model

            # enable dygraph mode
            paddle.disable_static(place)

            # load
            fc = paddle.jit.load(model_path)

            # inference
            fc.eval()
            x = paddle.randn([1, IMAGE_SIZE], 'float32')
            pred = fc(x)

            # fine-tune
            fc.train()
            loss_fn = nn.CrossEntropyLoss()
            adam = opt.Adam(learning_rate=0.001, parameters=fc.parameters())
            loader = paddle.io.DataLoader(dataset,
                places=place,
                batch_size=BATCH_SIZE,
                shuffle=True,
                drop_last=True,
                num_workers=2)
            for epoch_id in range(EPOCH_NUM):
                for batch_id, (image, label) in enumerate(loader()):
                    out = fc(image)
                    loss = loss_fn(out, label)
                    loss.backward()
                    adam.step()
                    adam.clear_grad()
                    print("Epoch {} batch {}: loss = {}".format(
                        epoch_id, batch_id, np.mean(loss.numpy())))
    )r   r   r   Z
_construct)r   r   r   r   r9   r9   r:   r2   f  s    `r2   feed_fetch_t_c                 C   s   t | tsJ t |ttfs|g}t  }t|}td0 | | }t |ttfs.|g}n|}t|dd}	||||	||\}
}}}|	  W d    n1 sQw   Y  t
d  t|
}W d    n1 siw   Y  |||||fS )NTr   )rF   )r=   r   r?   r@   r*   Z_get_program_desc_tracerrI   r   Zcreate_program_descresetr)   r;   )r   r<   Zfeed_prefixZfetch_prefixZ
tmp_prefixZtracerZvar_listZoriginal_outputsr   Zout_varsr7   
feed_namesfetch_namesr   r8   r9   r9   r:   _traceK  s(   





r   c                   @   s~   e Zd ZdZdd Zedd ZdddZee	d	d
 Z
dddZedd Zdd Zedd Zdd ZedddZdS )r.   a  
    :api_attr: imperative

    TracedLayer is used to convert a forward dygraph model to a static
    graph model. This is mainly used to save the dygraph model for online
    inference using C++. Besides, users can also do inference in Python
    using the converted static graph model, which usually has better
    performance than the original dygraph model.

    TracedLayer would run the static graph model using :code:`Executor`
    and :code:`CompiledProgram` . The static graph model would share
    parameters with the dygraph model.

    All TracedLayer objects should not be created by constructor and should
    be created by static method :code:`TracedLayer.trace(layer, inputs)` .

    The TracedLayer can only be used to convert the data-independent dygraph
    model into the static graph model, which means the dygraph model should
    be independent with the tensor data and shape.
    c                 C   s~   || _ || _|| _|| _t | _t | _|D ]}|	 
 }| j|j
 }|| qt| j| _d | _d | _d | _d S rH   )_program_feed_names_fetch_names_paramsr(   _placer   r   _scoper   r   rG   r   r   r    _exe_compiled_program_build_strategy_exec_strategy)rr   r8   r   r   r   pr   Z
dst_tensorr9   r9   r:   rs     s   

zTracedLayer.__init__c                 C   rt   rH   )r   rq   r9   r9   r:   r8     rv   zTracedLayer.programTc                 C   sD   t | jjD ]}| j|}|jD ]}|dr|d| qqd S )Nis_test)ranger   Z
num_blocksr   opsZhas_attrZ	_set_attr)rr   r  Zblock_idr   opr9   r9   r:   _switch  s   

zTracedLayer._switchc                 C   sF   t | tsJ dt| t| |\}}}}}t||||}||fS )a?  
        This method is the only allowed method to create TracedLayer object.
        It would call the :code:`layer(*inputs)` method to run the dygraph
        model and convert it into a static graph model.

        Args:
            layer (paddle.nn.Layer): the layer object to be traced.
            inputs (list(Tensor)|tuple(Tensor)|Tensor): the input tensors of
                the layer object.

        Returns:
            tuple: A tuple of 2 items, whose the first item is the output of
                :code:`layer(*inputs)` , and the second item is the created
                TracedLayer object.

        Examples:
            .. code-block:: python:

                import paddle

                class ExampleLayer(paddle.nn.Layer):
                    def __init__(self):
                        super(ExampleLayer, self).__init__()
                        self._fc = paddle.nn.Linear(3, 10)

                    def forward(self, input):
                        return self._fc(input)


                layer = ExampleLayer()
                in_var = paddle.uniform(shape=[2, 3], dtype='float32')
                out_dygraph, static_layer = paddle.jit.TracedLayer.trace(layer, inputs=[in_var])

                # run the static graph model using Executor inside
                out_static_graph = static_layer([in_var])

                print(len(out_static_graph)) # 1
                print(out_static_graph[0].shape) # (2, 10)

                # save the static graph model for inference
                static_layer.save_inference_model(dirname='./saved_infer_model')

        zhThe type of 'layer' in fluid.dygraph.jit.TracedLayer.trace must be fluid.dygraph.Layer, but received {}.)r=   r   rC   rD   r   r.   )r   r<   Zoutsprogfeedfetchr   Ztracedr9   r9   r:   trace  s   .zTracedLayer.traceNc                 C   sj   | j du s	J dt|tdtfsJ dt|t|tdtfs-J dt||| _|| _dS )a  
        Set the strategies when running static graph model.

        Args:
            build_strategy (BuildStrategy, optional): build strategy of
                :code:`CompiledProgram` inside TracedLayer. Default None.
            exec_strategy (ExecutionStrategy, optional): execution strategy of
                :code:`CompiledProgram` inside TracedLayer. Default None.

        Returns:
            None

        Examples:
            .. code-block:: python:

                import paddle

                class ExampleLayer(paddle.nn.Layer):
                    def __init__(self):
                        super(ExampleLayer, self).__init__()
                        self._fc = paddle.nn.Linear(3, 10)

                    def forward(self, input):
                        return self._fc(input)

                layer = ExampleLayer()
                in_var = paddle.uniform(shape=[2, 3], dtype='float32')

                out_dygraph, static_layer = paddle.jit.TracedLayer.trace(layer, inputs=[in_var])

                build_strategy = paddle.static.BuildStrategy()
                build_strategy.enable_inplace = True

                exec_strategy = paddle.static.ExecutionStrategy()
                exec_strategy.num_threads = 2

                static_layer.set_strategy(build_strategy=build_strategy, exec_strategy=exec_strategy)
                out_static_graph = static_layer([in_var])

        NzCannot set strategy after runzxThe type of 'build_strategy' in fluid.dygraph.jit.TracedLayer.set_strategy must be fluid.BuildStrategy, but received {}.z{The type of 'exec_strategy' in fluid.dygraph.jit.TracedLayer.set_strategy must be fluid.ExecutionStrategy, but received {}.)r  r=   rD   r
   rC   r   r  r  )rr   r]   exec_strategyr9   r9   r:   set_strategy  s"   )
zTracedLayer.set_strategyc                 C   s"   t | jj| j| j| jd| _d S )N)r]   r  Zplaces)r   r   Zwith_data_parallelr  r  r   r  rq   r9   r9   r:   _compile  s   zTracedLayer._compilec                 C   s   t |ttfsJ dt|t| jksJ i }t r0t|| jD ]\}}|  ||< q!|S t|| jD ]\}}|||< q6|S )Nz-Inputs should be a list or tuple of variables)	r=   r?   r@   r~   r   r,   zipr   r   )rr   r<   Z	feed_dictxr   r9   r9   r:   _build_feed  s   
zTracedLayer._build_feedc                 C   s   | j j| j|| jdS )N)r  Z
fetch_list)r  runr  r   )rr   r  r9   r9   r:   _run!  s   
zTracedLayer._runc                 C   sP   t | j | jd u r|   | | |W  d    S 1 s!w   Y  d S rH   )r!   r  r  r  r  r  )rr   r<   r9   r9   r:   __call__'  s
   
$zTracedLayer.__call__c                 K   s  t |dtd t |dtdtfd t|tr#|D ]	}t |dtd qt |dtdtfd t|tr?|D ]	}t |dtd q5|dd	}tj	|}|d
krSt
dtj|}|rftj|sft| ddlm}	 dd }
t| jN |
| j|}|
| j|}g }|D ]}| j j|d}|dusJ d||| q|t }|t }|	|||| j| j |||d W d   dS 1 sw   Y  dS )aW	  
        Save the TracedLayer to a model for inference. The saved
        inference model can be loaded by C++ inference APIs.

        ``path`` is the prefix of saved objects, and the saved translated program file
        suffix is ``.pdmodel`` , the saved persistable variables file suffix is ``.pdiparams`` .

        Args:
            path(str): The path prefix to save model. The format is ``dirname/file_prefix`` or ``file_prefix``.
            feed (list[int], optional): the input variable indices of the saved
                inference model. If None, all input variables of the
                TracedLayer object would be the inputs of the saved inference
                model. Default None.
            fetch (list[int], optional): the output variable indices of the
                saved inference model. If None, all output variables of the
                TracedLayer object would be the outputs of the saved inference
                model. Default None.
            kwargs: Supported keys including 'clip_extra'.set to True if you want to clip extra information for every operator.

        Returns:
            None

        Examples:
            .. code-block:: python:

                import numpy as np
                import paddle

                class ExampleLayer(paddle.nn.Layer):
                    def __init__(self):
                        super(ExampleLayer, self).__init__()
                        self._fc = paddle.nn.Linear(3, 10)

                    def forward(self, input):
                        return self._fc(input)

                save_dirname = './saved_infer_model'
                in_np = np.random.random([2, 3]).astype('float32')
                in_var = paddle.to_tensor(in_np)
                layer = ExampleLayer()

                out_dygraph, static_layer = paddle.jit.TracedLayer.trace(layer, inputs=[in_var])
                static_layer.save_inference_model(save_dirname, feed=[0], fetch=[0])

                paddle.enable_static()
                place = paddle.CPUPlace()
                exe = paddle.static.Executor(place)
                program, feed_vars, fetch_vars = paddle.static.load_inference_model(save_dirname,
                                                    exe)

                fetch, = exe.run(program, feed={feed_vars[0]: in_np}, fetch_list=fetch_vars)
                print(fetch.shape) # (2, 10)
        r   z2fluid.dygraph.jit.TracedLayer.save_inference_modelr  Nzeach element of feedr  zeach element of fetchr   Tr   r   r   r   c                    s   |d u r S  fdd|D S )Nc                    s   g | ]} | qS r9   r9   )r   idxall_varsr9   r:   r     s    zLTracedLayer.save_inference_model.<locals>.get_feed_fetch.<locals>.<listcomp>r9   )r  Zpartial_varsr9   r  r:   get_feed_fetch  s   z8TracedLayer.save_inference_model.<locals>.get_feed_fetchz{} cannot be found)r   r   r   r   r   rz   r   r   )r   r   rD   r?   r=   r   r   r   r   r   r   r   r   r   r   r   r!   r  r   r   r   Zglobal_blockr   rC   r>   r   r   r  r   )rr   r   r  r  rM   r   r   r   r   r   r  r   Ztarget_var_namesr   r   Z
target_varrz   r   r9   r9   r:   r   .  sh   7


"z TracedLayer.save_inference_model)T)NN)rT   rS   r   rV   rs   r^   r8   r  staticmethodr+   r  r  r   r  r  r  r  r   r9   r9   r9   r:   r.   l  s$    


45

r.   )r<   )NNNFrH   )F)r   r   r   )b
__future__r   r   r   r   	functoolscollectionsr   r   	threadingtypingr   r   r   r   r|   r   Zpaddle.fluidr   r	   Zpaddle.fluid.compilerr
   r   r   Zpaddle.fluid.data_feederr   Zpaddle.fluid.layers.utilsr   r   Zpaddle.fluid.dygraph.baser   r   Z&paddle.fluid.dygraph.dygraph_to_staticr   Z8paddle.fluid.dygraph.dygraph_to_static.convert_call_funcr   r   Z4paddle.fluid.dygraph.dygraph_to_static.logging_utilsr   r   Z9paddle.fluid.dygraph.dygraph_to_static.program_translatorr   r   r   Zpaddle.fluid.dygraph.ior   r   r   r   r   Zpaddle.fluid.dygraph.layersr   Zpaddle.fluid.executorr    r!   Zpaddle.fluid.frameworkr"   r#   r$   r%   r&   r'   r(   r)   r*   r+   r,   Zpaddle.fluid.wrapped_decoratorr-   __all__r;   rA   rI   rR   r0   rZ   r/   r3   objectrh   r   r   r   r   r   Lockr   r   r   r   r   r   r   r   r1   r2   r   r.   r9   r9   r9   r:   <module>   s    

?

W([
2)'
9	
"   7
 e 