U
    d[                  -   @   s   d dl mZmZmZ d dlmZ d dlmZ d dl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 d d	lZd
dddddddddddddddddddddd d!d"d#d$d%d&d'd(d)d*d+d,d-d.d/d0d1d2d3d4d5d6g-ZG d7d8 d8eZd;d9d:Zd	S )<    )corescope	workspace)db_input)parameter_info)parameter_sharing_context)OptimizerContextDEFAULT_OPTIM)RegularizerContext)	viewitemsviewkeys)chainNZAccuracyZAdamZAddZAdagradZSparseAdagradZAdadeltaZSparseAdadeltaZAveragedLossZCastZ
CheckpointZConstantFillZCopyZCopyGPUToCPUZCopyCPUToGPUZDequeueBlobsZEnsureCPUOutputZ
ExpandDimsZFlattenZFlattenToVecZLabelCrossEntropyZLearningRateZMakeTwoClassZMatMulZNCCLAllreduceZ	NHWC2NCHWZPackSegmentsZPrintZPReluZReduceFrontSumZScaleZScatterWeightedSumZSigmoidZSortedSegmentSumZSnapshotZSoftmaxZSoftmaxWithLossZSquaredL2DistanceZSqueezeStopGradientZ	SummarizeZTanhZ	TransposeZUnpackSegmentsZWeightedSumZ	YellowFinc                   @   s  e Zd ZdZd?ddZedd Zd	d
 Zdd Zdd Z	dd Z
d@ddZdd ZdAddZdBddZedd ZdCddZdd Zdd  Zd!d" Zd#d$ Zd%d& Zd'd( ZdDd)d*Zd+d, Zd-d. ZdEd/d0ZdFd1d2Zd3d4 Zd5d6 Zd7d8 Zd9d: Z d;d< Z!d=d> Z"dS )GModelHelpera  A helper model so we can manange models more easily. It contains net def
    and parameter storages. You can add an Operator yourself, e.g.

        model = model_helper.ModelHelper(name="train_net")
        # init your weight and bias as w and b
        w = model.param_init_net.XavierFill(...)
        b = model.param_init_net.ConstantFill(...)
        fc1 = model.FC([input, w, b], output, **kwargs)

    or you can use helper functions in brew module without manually
    defining parameter initializations and operators.

        model = model_helper.ModelHelper(name="train_net")
        fc1 = brew.fc(model, input, output, dim_in, dim_out, **kwargs)

    NTFc                 C   s   |pd| _ t| j | _|d k	rJ|j| _|j| _|j| _|j| _|j| _n*t| j d | _i | _g | _i | _g | _g | _	g | _
d| _|| _|| _|| _g | _g | _dddd| _|d k	r| j| d S )Nmodel_initFZNCHWT)orderZ	use_cudnnZcudnn_exhaustive_search)namer   Netnetparam_init_netparam_to_gradparams_parameters_info_computed_params_param_info_deprecated_devicesgradient_ops_addedinit_paramsallow_not_known_opsskip_sparse_optimweightsbiases
_arg_scopeupdate)selfr   r   r   r    Zparam_model	arg_scope r'   >/tmp/pip-unpacked-wheel-ua33x9lu/caffe2/python/model_helper.py__init__^   s6    

zModelHelper.__init__c                 C   s   | j S N)r#   r%   r'   r'   r(   r&      s    zModelHelper.arg_scopec                 C   s   | j S r*   )r   r+   r'   r'   r(   get_name   s    zModelHelper.get_namec                 C   sL   | j  jD ]:}t||jkr|jD ] }|jdkr$t|j    S q$qd S )Nshape)	r   Protoopstroutputargr   listZints)r%   paramr/   r2   r'   r'   r(   _infer_param_shape   s    

zModelHelper._infer_param_shapec              	   C   s   t | jt | jkst| jt | jd  D ]D}t|tjsLtdt| | j	t
jt | j|| |d q,| jD ]}| j|j|_qxd S )N!Param %s must be a BlobReference!)param_idr4   r-   )lenr   r   AssertionError
isinstancer   BlobReference
ValueErrorr0   appendr   ParameterInfor5   r   getr   grad)r%   r4   infor'   r'   r(   _update_param_info_deprecated   s    



z)ModelHelper._update_param_info_deprecatedc                 C   s$   |pg }t |trt|S t|gS r*   )r:   r3   set)r%   tagsr'   r'   r(   _normalize_tags   s    zModelHelper._normalize_tagsc           	      C   s   t |tjrt|}nt |tr,t|}ntd|| jkr^| j| j|ksRt	| j| j
S |jt|| j|d}t }| |D ]}||r|||_q|js|tr|t|_t }||_|| j|< | |j
| |j
S )a  
        Creates parameter with a given name and initializer.

        If param_name is instance of BlobRefernce - then this blob will be used
        to store parameter (no any logic will affect it's location).

        If param_name is instance of a string type, then the final blob will
        be created in the CurrentNameScope with the respect of all parameter
        sharing logic, i.e. 'resolved_name_scope/param_name'.

        Parameter sharing logic is going to override CurrentNameScope according
        to the rules that are specified through ParameterSharing contexts,
        all ParameterSharing contexts are applied recursively until there are no
        extra overrides present, where on each step the best match will be
        applied first.

        The following examples should clarify the way ParameterSharing logic
        works:

        As an example if this function is called with parameter 'w':
        a. Call from some scope 'global_scope' with no Parameter sharing:
          'global_scope/w'
        b. Call from scope 'scope_b', with override {'scope_b': 'scope_a'}:
          'scope_a/w'
        c. Call from scope 'scope_a', with override {'scope_a': ''}:
          'scope_a/w'
        d. Call from scope 'scope_b/shared', with overrides
          {'scope_b/shared': 'scope_b', 'scope_b': 'scope_a'}:
          'scope_a/w'
        d. Call from scope 'scope_b/unshared', with overrides
          {'scope_b/shared': 'scope_b', 'scope_b': 'scope_a'}:
          'scope_a/unshared/w'
        zUnsupported type for param_name)
param_nameZinit_netr-   )r:   r   r;   r0   r   Zget_parameter_name	TypeErrorr   r-   r9   Zblobcreate_paramr   r   currentrE   Zhas_optimizerZget_optimizerZ	optimizerr	   r
   ZregularizerAddParameter)	r%   rF   r-   ZinitializerrD   
param_infoZoptim_contexttagZreg_contextr'   r'   r(   rH      s4    %




zModelHelper.create_paramc                 C   s(   t |tjstd|| j|d S )NzParam {} is not a BlobReference)r:   r   r;   r9   formatr   r?   )r%   r4   r'   r'   r(   get_param_info   s    zModelHelper.get_param_infoc              	   C   s   t d |   | | |d k	rX| j d k	rX| j  |}| j  | }|d k	rd|n| 	|}t
|tjstdt| | jtjt| j||||d | jd S )Nzadd_param method is DEPRECATEDr6   )r7   r4   r-   keylength)loggingwarningrB   rJ   r   Zinput_recordZfield_blobsindexfield_namesr5   r:   r   r;   r<   r0   r   r=   r   r>   r8   )r%   r4   rO   r-   rP   idxr'   r'   r(   add_param_DEPRECATED   s"    


z ModelHelper.add_param_DEPRECATEDc                 C   st   t |tjst| |}tjj|kr4| j	| n| j
	| tjj|krX| j	| tjj|krp| j	| d S r*   )r:   r   r;   r9   rE   r   ZParameterTagsZCOMPUTED_PARAMr   r=   r   ZWEIGHTr!   ZBIASr"   )r%   r4   rD   r'   r'   r(   rJ     s    
zModelHelper.AddParameterc                 C   s6   | d krt  S | dks$| t jr(| S | t j S d S )N )r   ZCurrentNameScopeendswithZ_NAMESCOPE_SEPARATOR	namescoper'   r'   r(   _NormalizeNamescope  s
    zModelHelper._NormalizeNamescopec                    s8   t    dkr | jdd S  fdd| jD S dS )z9
        Returns the params in current namescope
        rX   Nc                    s   g | ]}|   r|qS r'   ZGetNameScope
startswith.0prZ   r'   r(   
<listcomp>$  s    z)ModelHelper.GetParams.<locals>.<listcomp>)r   r\   r   )r%   r[   Z	top_scoper'   rZ   r(   	GetParams  s    
zModelHelper.GetParamsc                 C   s
   | j  S r*   )r   r.   r+   r'   r'   r(   r.   '  s    zModelHelper.Protoc                 C   s
   | j  S r*   )r   r.   r+   r'   r'   r(   	InitProto*  s    zModelHelper.InitProtoc                 O   s    | j j|| | jj|| d S r*   )r   RunAllOnGPUr   )r%   argskwargsr'   r'   r(   re   -  s    zModelHelper.RunAllOnGPUc                 K   s    | j jg |f||d|}|S )N)dbdb_type)r   CreateDB)r%   blob_outrh   ri   rg   Zdbreaderr'   r'   r(   rj   1  s      zModelHelper.CreateDBc                 O   s   | j rtd|   d| _ | jj||| _| | j| _| j	 D ]4\}}| 
|}|rb||_qDtjd ||d| j|< qD| jS )Nz*You cannot run AddGradientOperators twice.T)r7   r4   r@   )r   RuntimeErrorValidater   AddGradientOperatorsgrad_mapget_param_to_gradr   r   itemsrN   r@   r   r>   r   )r%   rf   rg   r4   r@   rK   r'   r'   r(   rn   6  s     
z ModelHelper.AddGradientOperatorsc                 C   s@   i }| j std|D ]$}t|| jkr| jt| ||< q|S )zp
        Given a list of parameters returns a dict from a parameter
        to a corresponding gradient
        z+You need to run AddGradientOperators first.)r   rl   r0   ro   )r%   r   r   ra   r'   r'   r(   rp   N  s    zModelHelper.get_param_to_gradc                    s8    j std j}|r" |} fddt|D S )zy
        Returns a map for param => grad.
        If params is not specified, all parameters will be considered.
        z'Need to call AddGradientOperators firstc                    s,   g | ]$\}} j rt|tjs |qS r'   )r    r:   r   ZGradientSlicerN   )r`   r4   r@   r+   r'   r(   rb   j  s   z8ModelHelper.GetOptimizationParamInfo.<locals>.<listcomp>)r   rl   r   rp   r   )r%   r   r   r'   r+   r(   GetOptimizationParamInfo^  s    

z$ModelHelper.GetOptimizationParamInfoc                 C   st   dd | j D }t|}g }t|t|krpt|}t|D ]2\}}|dkr<||d  |kr<||kr<|| q<|S )z,
        Check for duplicate params
        c                 S   s   g | ]}t |qS r'   r0   r_   r'   r'   r(   rb   v  s     z)ModelHelper._Validate.<locals>.<listcomp>r      )r   rC   r8   sorted	enumerater=   )r%   Zparams_listZ
params_setdupesjra   r'   r'   r(   	_Validater  s    zModelHelper._Validatec                 C   s"   |   }|g kstd|d S )NzDuplicate params: {})ry   r9   rM   )r%   rw   r'   r'   r(   rm     s    zModelHelper.Validatec                    s8   t    dkr | jdd S  fdd| jD S dS )a  
        Returns the computed params in current namescope. 'Computed params'
        are such parameters that are not optimized via gradient descent but are
        directly computed from data, such as the running mean and variance
        of Spatial Batch Normalization.
        rX   Nc                    s   g | ]}|   r|qS r'   r]   r_   rZ   r'   r(   rb     s    z1ModelHelper.GetComputedParams.<locals>.<listcomp>)r   r\   r   r%   r[   r'   rZ   r(   GetComputedParams  s    
zModelHelper.GetComputedParamsc                 C   s   |  || | S r*   )rc   r{   rz   r'   r'   r(   GetAllParams  s    zModelHelper.GetAllParamsc                 K   s(   t |dkstdt| ||||f|S )zTensorProtosDBInput.r   zYou cannot pass reader to model_helper.TensorProtosDBInput.
               Use model.net.TensorProtosDBInput instead to create the op.)r8   r9   r   )r%   Zunused_blob_inrk   Z
batch_sizerh   ri   rg   r'   r'   r(   TensorProtosDBInput  s        zModelHelper.TensorProtosDBInputc                 C   s   t | jdkstd| jS )Nr   z6Use data_parallel_model to run model on multiple GPUs.)r8   r   r9   r+   r'   r'   r(   
GetDevices  s    zModelHelper.GetDevicesc                 C   s~   | drt|t|sFtd| d d dtj| d |tkrr| j	sbtd
|td
| | j|S )	z?Catch-all for all other operators, mostly those without params.__zMethod z is not a registered operator.z Did you mean: [,]z#Operator {} is not known to be safezCYou are creating an op that the ModelHelper does not recognize: {}.)r^   AttributeErrorr   Z
IsOperatorjoinr   CZnearby_opnames_known_working_opsr   rM   rR   rS   r   __getattr__)r%   Zop_typer'   r'   r(   r     s*    


zModelHelper.__getattr__c                 C   s"   t tttt| t| jtS r*   )ru   rC   r   dirtyper   __dict__r   r+   r'   r'   r(   __dir__  s
    
zModelHelper.__dir__c                 C   sd   | j j| jd dd}| jD ]}|jd |_q || j | j dr`| j j	| _	|S )zr Return param_init_net + net Net.
        Returns:
          'core.Net' containing param_init_net and net
        Z_complete_netT)keep_schema/param_init_netr   )
r   Cloner   r.   r/   
debug_infoZ	AppendNetr   ZHasFieldr   )r%   Znew_netr/   r'   r'   r(   GetCompleteNet  s     zModelHelper.GetCompleteNetc                 C   s~   g }g }t | jD ]*\}}|jdr6|| q|| q|j| d d|dd| _|j| d d|dd| _	dS )z construct init net and train net from complete_net
        Inputs:
          net: 'core.Net' containing param_init_net and train net
        r   z/generated_param_init_netT)r   Z
op_id_maskZupdate_external_listz/generated_netN)
rv   r.   r/   r   rY   r=   r   Namer   r   )r%   r   Zparam_op_maskZtrain_op_maskrV   r/   r'   r'   r(   ConstructInitTrainNetfromNet  s$    

z(ModelHelper.ConstructInitTrainNetfromNet)NTTFNN)N)NNN)N)NF)N)N)N)#__name__
__module____qualname____doc__r)   propertyr&   r,   r5   rB   rE   rH   rN   rW   rJ   staticmethodr\   rc   r.   rd   re   rj   rn   rp   rr   ry   rm   r{   r|   r}   r~   r   r   r   r   r'   r'   r'   r(   r   L   sH         
$

I






r   c              	      s<  t | jd }| }t| j}t| j}	dd  D  t| }
dd D t }t}dkrri |dk	r|
t| }
t| j	z$t
 fddttD }W n" tk
r   td Y nX z$tfd	dttD }W n$ tk
r    td
Y nX dd }fdd}||d  D ]V}|
|jr||jdkr|jD ]}|jdkr|td n~|jdkrl|jj	D ]8}||j ||j |dk	r|j|j_|j|j_q||jj ||jj |t|jj| ql|dk	r,|j|j_|j|j_|| |j	|g |
|j |t|j| |t|j|	 n t d|jt|j!|
 qF|j| |j| ||j ||j g } D ]*}|kr|"|  n
|"| q|j	D ]}||j ||j q|tt|jt| fS )a  
    Takes a model net for training and returns a net which can be
    used for prediction. For example, all gradient operators and
    input operators are removed.
    @param net_proto protobuf of the net you want to process (net.Proto())
    @param input_blobs list/set of blob names that are the inputs of predictor
    @param output_blobs list/set of blob names that are outputs of predictor
    @param device optional device option that is assigned
    @param renames dictionary of blob name to a new name (optional)
    @param disabled_inputs optional set of blobs that are 'switched off'. This
                will cause branches with those blobs as inputs to be removed
    Z_predictc                 S   s   h | ]}t |qS r'   rs   r`   br'   r'   r(   	<setcomp>  s     z&ExtractPredictorNet.<locals>.<setcomp>c                 S   s   h | ]}t |qS r'   rs   r   r'   r'   r(   r   
  s     Nc                    s.   g | ]&}  | jr| jd kr|qS )r   )intersectioninputr   r`   rx   )input_blobsopsr'   r(   rb     s    z'ExtractPredictorNet.<locals>.<listcomp>zNo ops with input={}c                    s    g | ]}  | jr|qS r'   )r   r1   r   )r   output_blobsr'   r(   rb   #  s   zNo ops with output={}c                 S   s:   | j D ].}|jdkr|jdkrtddt|  qd S )NZis_testr   ziAn operator had is_test=0, did you try to extract a predictor from a train model (instead of test model)?z Op was: {})r2   r   i	ExceptionrM   r0   )r/   r2   r'   r'   r(   validate_op+  s    
z(ExtractPredictorNet.<locals>.validate_opc                    sJ   | d d  }t |D ]\}}| kr | ||< q| d d = | | d S r*   )rv   extend)Z
proto_listZnew_listrx   r   )renamesr'   r(   rename_list6  s    
z(ExtractPredictorNet.<locals>.rename_listrt   ZRecurrentNetworkZbackward_step_netnZstep_netzOp {} had unknown inputs: {})#r   r   r   r.   rC   Zexternal_inputZexternal_outputunionr3   r/   minranger8   r<   r   rM   max
issupersetr   r   r2   Z
ClearFieldr0   r   r1   Zdevice_typeZdevice_optionZ	device_idr$   r   r   rR   debug
differencer=   )Z	net_protor   r   Zdevicer   Zdisabled_inputsZpredict_netZpredict_protoZorig_external_inputsZorig_external_outputsZknown_blobsZexternal_inputsZexternal_outputsZfirst_op_with_inputZlast_op_with_outputr   r   r/   r2   Zstep_opZrenamed_input_blobsr   r'   )r   r   r   r   r(   ExtractPredictorNet  s    












 




r   )NNN)Zcaffe2.pythonr   r   r   Zcaffe2.python.helpers.db_inputr   Zcaffe2.python.modelingr   Z(caffe2.python.modeling.parameter_sharingr   Zcaffe2.python.optimizer_contextr   r	   Z!caffe2.python.regularizer_contextr
   Zfuture.utilsr   r   	itertoolsr   rR   r   objectr   r   r'   r'   r'   r(   <module>   s|   1   *   